"""
版本管理API路由
"""
from typing import Any, List, Optional, Dict
from fastapi import APIRouter, Depends, HTTPException, status, Query, Body  # pyright: ignore[reportMissingImports]
from motor.motor_asyncio import AsyncIOMotorDatabase  # pyright: ignore[reportMissingImports]
from bson import ObjectId  # pyright: ignore[reportMissingImports]
from pymongo import ASCENDING, DESCENDING  # pyright: ignore[reportMissingImports]
from datetime import datetime, timezone
import logging
from pydantic import ValidationError  # pyright: ignore[reportMissingImports]

from app.api.deps import get_db, get_current_user

from app.models.version import (
    VersionCreate,
    VersionUpdate,
    VersionRequirementCreate,
    VersionTaskRelationCreate,
    VersionDefectRelationCreate,
    ReleaseRecordCreate,
    ReleaseRequest,
    RollbackRequest,
    ReleaseType,
    Environment,
    ReleaseStatus
)
from app.schemas.version import (
    VersionBasic,
    VersionWithStats,
    VersionDetail,
    VersionStatistics,
    VersionAnalyticsOverview,
    QualityMetrics,
    QualityMetricsSummary,
    VersionCompareInfo,
    ImpactAnalysis,
    ChangeHistory,
    ReleasePlan,
    VersionDependencies,
    VersionReport,
    TaskRelationInfo,
    DefectRelationInfo,
    RequirementRelationInfo,
    ReleaseRecordInfo,
    VersionOverviewResponse
)
from app.utils.state_utils import (
    validate_state_code,
    get_state_code_by_name_keywords
)
from app.core.permissions import Permissions
from app.core.response import success_response, paginated_response, ApiResponse, error_response
from app.core.state_validator import get_state_validator
from app.services.version_service import VersionService
from app.services.notification_service import NotificationService
from app.models.notification import NotificationCreate, NotificationType, RelatedObjectType
import asyncio

# 配置日志
logger = logging.getLogger(__name__)

# 数据验证工具函数
def validate_object_id(id_str: str, field_name: str = "ID") -> ObjectId:
    """验证并转换ObjectId"""
    try:
        return ObjectId(id_str)
    except Exception as e:
        logger.error(f"Invalid {field_name} format: {id_str}, error: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid {field_name} format"
        )

def validate_object_ids(id_list: List[str], field_name: str = "IDs") -> List[ObjectId]:
    """验证并转换ObjectId列表"""
    try:
        return [ObjectId(id_str) for id_str in id_list]
    except Exception as e:
        logger.error(f"Invalid {field_name} format in list: {id_list}, error: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid {field_name} format in list"
        )

async def validate_version_exists(db: AsyncIOMotorDatabase, version_id: ObjectId) -> dict:
    """验证版本是否存在"""
    version = await db.versions.find_one({"_id": version_id})
    if not version:
        logger.warning(f"Version not found: {version_id}")
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    return version

async def validate_project_permission(
    db: AsyncIOMotorDatabase, 
    project_id: ObjectId, 
    user_id: str,
    required_permission: str = None
) -> dict:
    """验证项目权限"""
    project = await db.projects.find_one({
        "_id": project_id,
        "$or": [
            {"created_by": ObjectId(user_id)},
            {"members.user_id": ObjectId(user_id)}
        ]
    })
    if not project:
        logger.warning(f"Project permission denied for user {user_id} on project {project_id}")
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    return project

def validate_date_range(start_date: Optional[str], end_date: Optional[str]) -> tuple:
    """验证日期范围"""
    try:
        start_dt = None
        end_dt = None
        
        if start_date:
            start_dt = datetime.fromisoformat(start_date.replace("Z", "+00:00"))
        if end_date:
            end_dt = datetime.fromisoformat(end_date.replace("Z", "+00:00"))
            
        if start_dt and end_dt and start_dt > end_dt:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Start date must be before end date"
            )
            
        return start_dt, end_dt
    except ValueError as e:
        logger.error(f"Invalid date format: start={start_date}, end={end_date}, error: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid date format. Use ISO format (YYYY-MM-DDTHH:MM:SSZ)"
        )

def validate_pagination_params(skip: int, limit: int) -> tuple:
    """验证分页参数"""
    if skip < 0:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Skip parameter must be non-negative"
        )
    if limit <= 0 or limit > 200:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Limit parameter must be between 1 and 200"
        )
    return skip, limit

async def handle_database_error(operation: str, error: Exception):
    """统一处理数据库错误"""
    logger.error(f"Database error in {operation}: {str(error)}")
    if "duplicate key" in str(error).lower():
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Resource already exists"
        )
    elif "timeout" in str(error).lower():
        raise HTTPException(
            status_code=status.HTTP_504_GATEWAY_TIMEOUT,
            detail="Database operation timeout"
        )
    else:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Database operation failed: {operation}"
        )


async def check_version_permission(
    db: AsyncIOMotorDatabase,
    version_id: ObjectId,
    current_user: dict,
    required_permission: str = Permissions.VERSION_READ
) -> dict:
    """
    检查版本访问权限
    返回版本信息和项目信息
    """
    # 查询版本
    version = await db.versions.find_one({"_id": version_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    user_id = ObjectId(current_user.get("user_id"))
    
    # 管理员或拥有相应权限的用户可以访问
    if "*" in user_permissions or required_permission in user_permissions:
        project = await db.projects.find_one({"_id": version["project_id"]}, {"name": 1})
        return {
            "version": version,
            "project": project
        }
    
    # 检查用户是否有项目访问权限
    project = await db.projects.find_one({
        "_id": version["project_id"],
        "$or": [
            {"is_public": True},
            {"created_by": user_id},
            {"members.user_id": user_id}
        ]
    })
    
    if not project:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    return {
        "version": version,
        "project": project
    }


async def get_accessible_project_ids(
    db: AsyncIOMotorDatabase,
    current_user: dict
) -> List[ObjectId]:
    """
    获取用户有权限访问的项目ID列表
    """
    user_permissions = current_user.get("permissions", [])
    
    # 管理员可以访问所有项目
    if "*" in user_permissions or Permissions.VERSION_READ_ALL in user_permissions:
        return []  # 空列表表示所有项目
    
    user_id = ObjectId(current_user.get("user_id"))
    project_query = {
        "$or": [
            {"is_public": True},
            {"created_by": user_id},
            {"members.user_id": user_id}
        ]
    }
    
    project_cursor = db.projects.find(project_query, {"_id": 1})
    accessible_project_ids = [project["_id"] async for project in project_cursor]
    
    return accessible_project_ids


async def check_project_access(
    db: AsyncIOMotorDatabase,
    project_id: ObjectId,
    current_user: dict,
    include_public: bool = True
) -> dict:
    """
    检查用户是否有项目访问权限
    """
    user_id = ObjectId(current_user.get("user_id"))
    user_permissions = current_user.get("permissions", [])
    
    # 管理员可以访问所有项目
    if "*" in user_permissions or Permissions.VERSION_READ_ALL in user_permissions:
        project = await db.projects.find_one({"_id": project_id})
        if project:
            return project
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Project not found"
        )
    
    # 构建查询条件
    query_conditions = [
        {"created_by": user_id},
        {"members.user_id": user_id}
    ]
    if include_public:
        query_conditions.append({"is_public": True})
    
    project = await db.projects.find_one({
        "_id": project_id,
        "$or": query_conditions
    })
    
    if not project:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    return project


def build_version_query_filters(
    search: Optional[str] = None,
    project_id: Optional[str] = None,
    status: Optional[str] = None,
    release_type: Optional[ReleaseType] = None,
    environment: Optional[Environment] = None,
    created_by: Optional[str] = None
) -> dict:
    """
    构建版本查询条件
    """
    query = {}
    
    if search:
        query["$or"] = [
            {"name": {"$regex": search, "$options": "i"}},
            {"description": {"$regex": search, "$options": "i"}},
            {"version_number": {"$regex": search, "$options": "i"}}
        ]
    
    if project_id:
        try:
            query["project_id"] = ObjectId(project_id)
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid project_id format"
            )
    
    if status:
        query["status"] = status
    
    if release_type:
        query["release_type"] = release_type
    
    if environment:
        query["environment"] = environment
    
    if created_by:
        try:
            query["created_by"] = ObjectId(created_by)
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid created_by ID format"
            )
    
    return query


# serialize_mongo_result 函数已迁移到 version_service.py，避免重复定义
from app.services.version_service import serialize_mongo_result


router = APIRouter()

@router.get("/", include_in_schema=False, response_model=None, summary="获取版本列表（分页）")
@router.get("", include_in_schema=True, response_model=None, summary="获取版本列表（分页）")
async def get_versions(
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(20, ge=1, le=200, description="返回的记录数"),
    search: Optional[str] = Query(None, description="搜索关键词"),
    project_id: Optional[str] = Query(None, description="项目ID筛选"),
    status: Optional[str] = Query(None, description="版本状态筛选"),
    release_type: Optional[ReleaseType] = Query(None, description="发布类型筛选"),
    environment: Optional[Environment] = Query(None, description="环境筛选"),
    created_by: Optional[str] = Query(None, description="创建者筛选"),
    sort_by: str = Query("created_at", description="排序字段"),
    sort_order: str = Query("desc", regex="^(asc|desc)$", description="排序方向"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本列表
    """
    try:
        # 验证分页参数
        skip, limit = validate_pagination_params(skip, limit)
        
        # 使用服务层
        service = VersionService(db)
        result = await service.get_versions(
            current_user=current_user,
            skip=skip,
            limit=limit,
            search=search,
            project_id=project_id,
            status=status,
            release_type=release_type,
            environment=environment,
            created_by=created_by,
            sort_by=sort_by,
            sort_order=sort_order
        )
        
        return paginated_response(
            items=result["items"],
            total=result["total"],
            page=result["page"],
            size=result["size"],
            message="获取版本列表成功"
        )
    except HTTPException:
        raise
    except Exception as e:
        await handle_database_error("get_versions", e)


@router.get("/overview", response_model=ApiResponse, summary="获取版本总览数据")
async def get_versions_overview(
    project_id: Optional[str] = Query(None, description="项目ID筛选"),
    status: Optional[str] = Query(None, description="版本状态筛选"),
    release_type: Optional[ReleaseType] = Query(None, description="发布类型筛选"),
    environment: Optional[Environment] = Query(None, description="环境筛选"),
    created_by: Optional[str] = Query(None, description="创建者筛选"),
    limit: int = Query(50, ge=1, le=200, description="返回的版本数量"),
    sort_by: str = Query("planned_release_date", description="排序字段"),
    sort_order: str = Query("desc", regex="^(asc|desc)$", description="排序方向"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> ApiResponse[VersionOverviewResponse]:
    """获取版本管理页面左侧总览数据"""
    service = VersionService(db)
    result = await service.get_versions_overview(
        current_user=current_user,
        project_id=project_id,
        status=status,
        release_type=release_type,
        environment=environment,
        created_by=created_by,
        limit=limit,
        sort_by=sort_by,
        sort_order=sort_order
    )
    return success_response(result)


@router.get("/count", response_model=ApiResponse, summary="获取版本总数")
async def get_versions_count(
    search: Optional[str] = Query(None, description="搜索关键词"),
    project_id: Optional[str] = Query(None, description="项目ID筛选"),
    status: Optional[str] = Query(None, description="版本状态筛选"),
    release_type: Optional[ReleaseType] = Query(None, description="发布类型筛选"),
    environment: Optional[Environment] = Query(None, description="环境筛选"),
    created_by: Optional[str] = Query(None, description="创建者筛选"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本总数
    """
    # 使用服务层
    service = VersionService(db)
    count = await service.get_versions_count(
        current_user=current_user,
        search=search,
        project_id=project_id,
        status=status,
        release_type=release_type,
        environment=environment,
        created_by=created_by
    )
    
    return success_response(data={"count": count}, message="获取版本总数成功")

# ========== 审批相关接口（必须在/{version_id}之前定义，避免路由冲突）==========

@router.post("/transition-approvals/{approval_id}/approve", response_model=ApiResponse, summary="审批流转申请")
async def approve_transition_request(
    approval_id: str,
    approval_data: dict = Body(...),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """审批流转申请"""
    try:
        approval_obj_id = ObjectId(approval_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid approval ID format"
        )
    
    approved = approval_data.get("approved", True)
    notes = approval_data.get("notes", "")
    
    # 检查权限
    service = VersionService(db)
    approval_service = service.approval_service
    
    try:
        result = await approval_service.approve_request(
            approval_obj_id,
            ObjectId(current_user.get("user_id")),
            approved,
            notes,
            current_user
        )
        
        message = "审批通过" if approved else "审批已拒绝"
        return success_response(data=result, message=message)
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )


@router.get("/transition-approvals/pending", response_model=ApiResponse, summary="获取待审批列表")
async def get_pending_approvals(
    project_id: Optional[str] = Query(None, description="项目ID筛选"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """获取待审批列表"""
    service = VersionService(db)
    approval_service = service.approval_service
    
    project_obj_id = None
    if project_id:
        try:
            project_obj_id = ObjectId(project_id)
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid project ID format"
            )
    
    approvals = await approval_service.get_pending_approvals(
        current_user,
        project_obj_id
    )
    
    return success_response(
        data={"approvals": approvals},
        message="获取待审批列表成功"
    )


@router.get("/transition-approvals/history", response_model=ApiResponse, summary="获取审批历史列表")
async def get_approval_history(
    project_id: Optional[str] = Query(None, description="项目ID筛选"),
    status: Optional[str] = Query(None, description="状态筛选（approved/rejected/cancelled）"),
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(20, ge=1, le=100, description="返回的记录数"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """获取审批历史列表（已审批、已拒绝、已取消）"""
    # 查询条件
    query: Dict[str, Any] = {
        "status": {"$in": ["approved", "rejected", "cancelled"]}
    }
    
    project_obj_id = None
    if project_id:
        try:
            project_obj_id = ObjectId(project_id)
            # 通过版本ID查找项目
            versions = await db.versions.find(
                {"project_id": project_obj_id},
                {"_id": 1}
            ).to_list(None)
            version_ids = [v["_id"] for v in versions]
            query["version_id"] = {"$in": version_ids}
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid project ID format"
            )
    
    if status:
        query["status"] = status
    
    # 查询审批记录
    cursor = db.version_transition_approvals.find(query).sort("created_at", -1).skip(skip).limit(limit)
    approvals = await cursor.to_list(None)
    
    # 获取总数
    total = await db.version_transition_approvals.count_documents(query)
    
    # 格式化数据
    formatted_approvals = []
    for approval in approvals:
        # 获取版本信息
        version = await db.versions.find_one({"_id": approval["version_id"]})
        version_name = version.get("name", "") if version else ""
        version_number = version.get("version_number", "") if version else ""
        
        # 获取申请人信息
        requester = await db.users.find_one({"_id": approval["requester_id"]})
        requester_name = requester.get("name", "") if requester else ""
        
        # 获取审批人信息
        approved_by_name = ""
        if approval.get("approved_by"):
            approver = await db.users.find_one({"_id": approval["approved_by"]})
            approved_by_name = approver.get("name", "") if approver else ""
        
        formatted_approvals.append({
            "id": str(approval["_id"]),
            "version_id": str(approval["version_id"]),
            "version_name": version_name,
            "version_number": version_number,
            "from_status": approval["from_status"],
            "to_status": approval["to_status"],
            "status": approval["status"],
            "reason": approval.get("reason", ""),
            "requester_id": str(approval["requester_id"]),
            "requester_name": requester_name,
            "requested_at": approval.get("requested_at", approval.get("created_at")),
            "approved_by": str(approval["approved_by"]) if approval.get("approved_by") else None,
            "approved_by_name": approved_by_name,
            "approved_at": approval.get("approved_at"),
            "approval_notes": approval.get("approval_notes", ""),
            "rejection_reason": approval.get("rejection_reason", ""),
            "cancelled_at": approval.get("cancelled_at")
        })
    
    return success_response(
        data={
            "approvals": formatted_approvals,
            "total": total,
            "skip": skip,
            "limit": limit
        },
        message="获取审批历史成功"
    )


@router.post("/transition-approvals/{approval_id}/cancel", response_model=ApiResponse, summary="取消审批申请")
async def cancel_approval_request(
    approval_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """取消审批申请"""
    try:
        approval_obj_id = ObjectId(approval_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid approval ID format"
        )
    
    service = VersionService(db)
    approval_service = service.approval_service
    
    try:
        result = await approval_service.cancel_request(
            approval_obj_id,
            ObjectId(current_user.get("user_id")),
            current_user
        )
        
        return success_response(data=result, message="取消审批申请成功")
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )


# ========== 版本状态流转相关接口（必须在/{version_id}之前定义，避免路由冲突）==========

@router.get("/{version_id}/completion", response_model=ApiResponse, summary="获取版本完成度")
async def get_version_completion(
    version_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """获取版本完成度统计"""
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    service = VersionService(db)
    
    version_doc = await db.versions.find_one({"_id": version_obj_id})
    if not version_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    await service._check_project_access(version_doc["project_id"], current_user)
    
    # 获取完成度
    completion_data = await service.get_completion_rate(version_obj_id)
    
    return success_response(data=completion_data, message="获取版本完成度成功")


@router.get("/{version_id}/transition-readiness", response_model=ApiResponse, summary="获取版本状态流转准备情况")
async def get_version_transition_readiness(
    version_id: str,
    target_status: Optional[str] = Query(None, description="目标状态（可选）"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """获取版本状态流转准备情况（还差什么条件）"""
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    service = VersionService(db)
    version_doc = await db.versions.find_one({"_id": version_obj_id})
    if not version_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    await service._check_project_access(version_doc["project_id"], current_user)
    
    # 获取流转准备情况
    readiness = await service.get_transition_readiness(version_obj_id, target_status)
    
    return success_response(data=readiness, message="获取流转准备情况成功")


@router.get("/{version_id}/allowed-transitions", response_model=ApiResponse, summary="获取版本允许的状态流转列表")
async def get_version_allowed_transitions(
    version_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """获取版本允许的状态流转列表"""
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    service = VersionService(db)
    version_doc = await db.versions.find_one({"_id": version_obj_id})
    if not version_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    await service._check_project_access(version_doc["project_id"], current_user)
    
    # 获取当前状态
    # 从状态管理系统获取默认状态
    from app.utils.state_utils import get_default_state_code
    default_status = await get_default_state_code(db, "version")
    current_status = version_doc.get("status") or default_status or ""
    
    # 获取流转规则
    from app.services.version_transition_rules import VersionTransitionRules
    rules = VersionTransitionRules.get_rules_by_from_status(current_status)
    
    # 转换为前端需要的格式
    allowed_transitions = []
    for rule in rules:
        allowed_transitions.append({
            "from_status": rule.from_status,
            "to_status": rule.to_status,
            "name": rule.name,
            "auto_trigger": rule.auto_trigger,
            "require_approval": rule.require_approval,
            "require_reason": rule.require_reason
        })
    
    return success_response(
        data={"allowed_transitions": allowed_transitions},
        message="获取允许的流转列表成功"
    )


@router.post("/{version_id}/transition-status", response_model=ApiResponse, summary="手动流转版本状态")
async def transition_version_status(
    version_id: str,
    transition_data: dict = Body(...),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """手动流转版本状态"""
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    new_status = transition_data.get("new_status")
    reason = transition_data.get("reason", "")
    comment = transition_data.get("comment", reason)
    
    if not new_status:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="new_status is required"
        )
    
    service = VersionService(db)
    version_doc = await db.versions.find_one({"_id": version_obj_id})
    if not version_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    await service._check_project_access(version_doc["project_id"], current_user)
    
    # 执行手工流转
    try:
        result = await service.manual_transition(
            version_doc,
            new_status,
            current_user,
            reason=reason,
            comment=comment
        )
    except HTTPException as exc:
        detail = exc.detail
        if isinstance(detail, dict):
            message = detail.get("message", "状态流转失败")
            extra_details = {k: v for k, v in detail.items() if k != "message"}
            return error_response(
                error_type="transition_failed",
                message=message,
                code=exc.status_code,
                details=extra_details or None
            )
        raise
    
    return success_response(data=result, message="状态流转成功")


@router.post("/{version_id}/transition-approval", response_model=ApiResponse, summary="提交状态流转审批申请")
async def submit_transition_approval(
    version_id: str,
    approval_data: dict = Body(...),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """提交状态流转审批申请"""
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    to_status = approval_data.get("to_status")
    reason = approval_data.get("reason", "")
    approval_flow_type = approval_data.get("approval_flow_type", "simple")
    
    if not to_status:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="to_status is required"
        )
    
    service = VersionService(db)
    version_doc = await db.versions.find_one({"_id": version_obj_id})
    if not version_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    await service._check_project_access(version_doc["project_id"], current_user)
    
    # 创建审批申请
    from app.services.version_approval_service import VersionApprovalService
    # 获取默认状态
    from app.utils.state_utils import get_default_state_code
    default_status = await get_default_state_code(db, "version")
    approval_service = VersionApprovalService(db)
    
    approval = await approval_service.create_approval_request(
        version_obj_id=version_obj_id,
        from_status=version_doc.get("status") or default_status or "",
        to_status=to_status,
        requester_id=ObjectId(current_user.get("user_id")),
        reason=reason,
        approval_flow_type=approval_flow_type,
        current_user=current_user
    )
    
    return success_response(data=approval, message="审批申请已提交")


@router.get("/{version_id}/work-items", response_model=ApiResponse, summary="获取版本工作项树")
async def get_version_work_items(
    version_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> ApiResponse:
    """获取指定版本下的需求、任务、缺陷树"""
    service = VersionService(db)
    result = await service.get_version_work_items(version_id, current_user)
    return success_response(result)


@router.get("/{version_id}/plan", response_model=ApiResponse, summary="获取版本规划视图数据")
async def get_version_plan_view(
    version_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> ApiResponse:
    """获取指定版本的规划视图数据"""
    service = VersionService(db)
    result = await service.get_version_plan_view(version_id, current_user)
    return success_response(result)


@router.get("/{version_id}/kanban", response_model=ApiResponse, summary="获取版本状态看板数据")
async def get_version_kanban(
    version_id: str,
    dimension: str = Query("requirement", description="看板维度：requirement/task/defect"),
    status: Optional[str] = Query(None, description="状态筛选，多个状态使用逗号分隔"),
    assignee_id: Optional[str] = Query(None, description="负责人筛选"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> ApiResponse:
    """获取版本状态看板数据"""
    service = VersionService(db)
    filters: Dict[str, Any] = {}
    if status:
        filters["status"] = [s.strip() for s in status.split(",") if s.strip()]
    if assignee_id:
        filters["assignee_id"] = assignee_id
    result = await service.get_version_kanban(
        version_id=version_id,
        current_user=current_user,
        dimension=dimension,
        filters=filters or None
    )
    return success_response(result)


@router.get("/{version_id}", response_model=ApiResponse, summary="获取版本详情")
async def get_version(
    version_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本详情
    """
    # 使用服务层
    service = VersionService(db)
    version_detail = await service.get_version(version_id, current_user)
    
    return success_response(data=version_detail, message="获取版本详情成功")

@router.post("/", include_in_schema=False, response_model=ApiResponse, summary="创建版本")
@router.post("", include_in_schema=True, response_model=ApiResponse, summary="创建版本")
async def create_version(
    version_data: VersionCreate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    创建版本
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_CREATE not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    # 验证项目是否存在且用户有权限
    try:
        project_obj_id = ObjectId(version_data.project_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid project ID format"
        )
    
    # 先检查项目是否存在
    project = await db.projects.find_one({"_id": project_obj_id})
    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Project not found"
        )
    
    # 权限检查：如果用户有管理员权限，允许创建版本
    user_id = ObjectId(current_user.get("user_id"))
    has_admin_permission = (
        "*" in user_permissions or 
        Permissions.ADMIN in user_permissions or
        Permissions.VERSION_CREATE in user_permissions
    )
    
    # 检查用户是否有权限访问项目
    has_project_access = (
        has_admin_permission or
        project.get("is_public", False) or
        project.get("created_by") == user_id or
        any(member.get("user_id") == user_id for member in project.get("members", []))
    )
    
    if not has_project_access:
        logger.warning(f"User {user_id} does not have access to project {project_obj_id}")
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Not enough permissions to create version for this project"
        )
    
    # 检查版本号是否在项目中唯一
    existing_version = await db.versions.find_one({
        "project_id": project_obj_id,
        "version_number": version_data.version_number
    })
    if existing_version:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Version number already exists in this project"
        )
    
    # 创建版本文档
    now = datetime.utcnow()
    # 获取默认状态
    from app.utils.state_utils import get_default_state_code
    default_status = await get_default_state_code(db, "version")
    # 使用dict()方法获取所有字段，包括可选字段
    version_dict = version_data.dict(exclude_unset=False)
    
    # 处理枚举类型的转换
    release_type_value = version_dict.get("release_type")
    if release_type_value and hasattr(release_type_value, 'value'):
        release_type_value = release_type_value.value
    
    environment_value = version_dict.get("environment")
    if environment_value and hasattr(environment_value, 'value'):
        environment_value = environment_value.value
    
    version_doc = {
        "name": version_data.name,
        "version_number": version_data.version_number,
        "description": version_data.description,
        "project_id": project_obj_id,
        "start_date": version_data.start_date,
        "end_date": version_data.end_date,
        "status": version_dict.get("status") or default_status or "",
        "release_type": release_type_value,
        "environment": environment_value,
        "planned_release_date": version_data.planned_release_date,
        "planned_work_hours": float(version_dict.get("planned_work_hours", 0.0) or 0.0),
        "actual_release_date": None,
        "release_notes": version_dict.get("release_notes"),
        "release_config": version_data.release_config.model_dump() if version_data.release_config else {},
        "metadata": version_dict.get("metadata") or {},
        "is_pinned": version_data.is_pinned if hasattr(version_data, 'is_pinned') else False,
        "created_by": ObjectId(current_user.get("user_id")),
        "created_at": now,
        "updated_at": now
    }
    
    # 插入版本
    result = await db.versions.insert_one(version_doc)
    
    # 返回创建的版本
    created_version = await db.versions.find_one({"_id": result.inserted_id})
    
    # 发送版本创建通知
    try:
        current_user_obj = await db.users.find_one({"_id": user_id})
        current_user_name = current_user_obj.get("name") or current_user_obj.get("username", "未知用户") if current_user_obj else "未知用户"
        project_name = project.get("name", "未知项目")
        
        # 确定通知接收者：项目成员
        notification_recipients = set()
        
        # 添加项目创建人（如果不是当前用户）
        if project.get("created_by") and str(project["created_by"]) != current_user["user_id"]:
            notification_recipients.add(str(project["created_by"]))
        
        # 添加项目成员（排除当前用户）
        for member in project.get("members", []):
            member_id = member.get("user_id")
            if member_id and str(member_id) != current_user["user_id"]:
                notification_recipients.add(str(member_id))
        
        # 发送通知
        notification_tasks = []
        version_id_str = str(result.inserted_id)
        
        for recipient_id in notification_recipients:
            notification_data = NotificationCreate(
                user_id=recipient_id,
                type=NotificationType.VERSION_CREATED,
                title=f"版本创建：{version_data.name}",
                content=f"{current_user_name} 在项目「{project_name}」中创建了版本「{version_data.name}」（{version_data.version_number}）",
                related_type=RelatedObjectType.VERSION,
                related_id=version_id_str,
                metadata={
                    "project_id": str(project_obj_id),
                    "project_name": project_name,
                    "operator_id": current_user["user_id"],
                    "operator_name": current_user_name,
                    "operator_avatar": current_user_obj.get("avatar") if current_user_obj else None
                }
            )
            notification_tasks.append(
                NotificationService.create_notification(
                    db=db,
                    notification_data=notification_data,
                    send_email=False
                )
            )
        
        # 异步发送所有通知
        if notification_tasks:
            asyncio.create_task(asyncio.gather(*notification_tasks, return_exceptions=True))
    except Exception as e:
        logger.warning(f"发送版本创建通知失败: {str(e)}")
    
    return success_response(data={
        "id": str(created_version["_id"]),
        "name": created_version["name"],
        "version_number": created_version["version_number"],
        "description": created_version.get("description"),
        "project_id": str(created_version["project_id"]),
        "start_date": created_version.get("start_date"),
        "end_date": created_version.get("end_date"),
        "status": created_version["status"],
        "release_type": created_version["release_type"],
        "environment": created_version["environment"],
        "planned_release_date": created_version.get("planned_release_date"),
        "actual_release_date": created_version.get("actual_release_date"),
        "planned_work_hours": float(created_version.get("planned_work_hours") or 0.0),
        "release_notes": created_version.get("release_notes"),
        "release_config": created_version.get("release_config", {}),
        "metadata": created_version.get("metadata", {}),
        "created_by": str(created_version["created_by"]),
        "created_at": created_version["created_at"],
        "updated_at": created_version["updated_at"]
    }, message="创建版本成功")

@router.put("/{version_id}", response_model=ApiResponse, summary="更新版本")
async def update_version(
    version_id: str,
    version_data: VersionUpdate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    更新版本
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 查询版本
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        # 检查是否是版本创建者或项目成员
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project and version["created_by"] != ObjectId(current_user.get("user_id")):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 构建更新数据
    update_data = {"updated_at": datetime.utcnow()}
    
    # 只更新提供的字段
    update_fields = version_data.dict(exclude_unset=True)
    
    # 如果更新版本号，检查是否在项目中唯一
    if "version_number" in update_fields and update_fields["version_number"] and update_fields["version_number"] != version["version_number"]:
        existing_version = await db.versions.find_one({
            "project_id": version["project_id"],
            "version_number": update_fields["version_number"],
            "_id": {"$ne": version_obj_id}
        })
        if existing_version:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Version number already exists in this project"
            )
    for field, value in update_fields.items():
        if field in ["release_config", "metadata"] and value:
            update_data[field] = value.model_dump() if hasattr(value, 'model_dump') else value
        elif field == "planned_work_hours":
            update_data[field] = float(value) if value is not None else 0.0
        else:
            update_data[field] = value
    
    # 更新版本
    await db.versions.update_one(
        {"_id": version_obj_id},
        {"$set": update_data}
    )
    
    # 返回更新后的版本
    updated_version = await db.versions.find_one({"_id": version_obj_id})
    
    # 发送版本更新通知
    try:
        user_id = ObjectId(current_user["user_id"])
        current_user_obj = await db.users.find_one({"_id": user_id})
        current_user_name = current_user_obj.get("name") or current_user_obj.get("username", "未知用户") if current_user_obj else "未知用户"
        
        # 获取项目信息
        project = await db.projects.find_one({"_id": version["project_id"]})
        project_name = project.get("name", "未知项目") if project else "未知项目"
        
        # 确定通知接收者：项目成员（排除当前用户）
        notification_recipients = set()
        
        # 添加项目创建人（如果不是当前用户）
        if project and project.get("created_by") and str(project["created_by"]) != current_user["user_id"]:
            notification_recipients.add(str(project["created_by"]))
        
        # 添加项目成员（排除当前用户）
        if project:
            for member in project.get("members", []):
                member_id = member.get("user_id")
                if member_id and str(member_id) != current_user["user_id"]:
                    notification_recipients.add(str(member_id))
        
        # 发送通知
        notification_tasks = []
        version_name = updated_version.get("name", "未知版本")
        
        for recipient_id in notification_recipients:
            notification_data = NotificationCreate(
                user_id=recipient_id,
                type=NotificationType.VERSION_UPDATED,
                title=f"版本更新：{version_name}",
                content=f"{current_user_name} 更新了项目「{project_name}」中的版本「{version_name}」",
                related_type=RelatedObjectType.VERSION,
                related_id=version_id,
                metadata={"project_id": str(version["project_id"]), "project_name": project_name}
            )
            notification_tasks.append(
                NotificationService.create_notification(
                    db=db,
                    notification_data=notification_data,
                    send_email=False
                )
            )
        
        # 异步发送所有通知
        if notification_tasks:
            asyncio.create_task(asyncio.gather(*notification_tasks, return_exceptions=True))
    except Exception as e:
        logger.warning(f"发送版本更新通知失败: {str(e)}")
    
    return success_response(data={
        "id": str(updated_version["_id"]),
        "name": updated_version["name"],
        "version_number": updated_version["version_number"],
        "description": updated_version.get("description"),
        "project_id": str(updated_version["project_id"]),
        "start_date": updated_version.get("start_date"),
        "end_date": updated_version.get("end_date"),
        "status": updated_version["status"],
        "release_type": updated_version["release_type"],
        "environment": updated_version["environment"],
        "planned_release_date": updated_version.get("planned_release_date"),
        "actual_release_date": updated_version.get("actual_release_date"),
        "planned_work_hours": float(updated_version.get("planned_work_hours") or 0.0),
        "release_notes": updated_version.get("release_notes"),
        "release_config": updated_version.get("release_config", {}),
        "metadata": updated_version.get("metadata", {}),
        "is_pinned": updated_version.get("is_pinned", False),
        "created_by": str(updated_version["created_by"]),
        "created_at": updated_version["created_at"],
        "updated_at": updated_version["updated_at"]
    }, message="更新版本成功")

@router.delete("/{version_id}", response_model=ApiResponse, summary="删除版本")
async def delete_version(
    version_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    删除版本
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 查询版本
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_DELETE not in user_permissions:
        # 检查是否是版本创建者或项目管理员
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {
                    "members": {
                        "$elemMatch": {
                            "user_id": ObjectId(current_user.get("user_id")),
                            "role": {"$in": ["admin", "manager"]}
                        }
                    }
                }
            ]
        })
        if not project and version["created_by"] != ObjectId(current_user.get("user_id")):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 检查版本是否已发布，已发布的版本不能删除 - 使用动态状态
    released_status_code = await get_state_code_by_name_keywords(db, "version", ["已发布", "发布", "released"])
    if released_status_code and version["status"] == released_status_code:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Cannot delete released version"
        )
    
    # 检查关联关系：任务、缺陷、需求、发布记录（测试用例和测试套件已移除，不再关联版本）
    task_relations_count = await db.version_task_relations.count_documents({"version_id": version_obj_id})
    defect_relations_count = await db.version_defect_relations.count_documents({"version_id": version_obj_id})
    requirement_relations_count = await db.version_requirement_relations.count_documents({"version_id": version_obj_id})
    release_records_count = await db.release_records.count_documents({"version_id": version_obj_id})
    
    # 如果存在关联关系，返回详细错误信息
    if (task_relations_count > 0 or defect_relations_count > 0 or requirement_relations_count > 0 or 
        release_records_count > 0):
        relation_details = []
        if task_relations_count > 0:
            relation_details.append(f"任务关联({task_relations_count}个)")
        if defect_relations_count > 0:
            relation_details.append(f"缺陷关联({defect_relations_count}个)")
        if requirement_relations_count > 0:
            relation_details.append(f"需求关联({requirement_relations_count}个)")
        if release_records_count > 0:
            relation_details.append(f"发布记录({release_records_count}个)")
        
        return error_response(
            error_type="RELATION_EXISTS",
            message=f"无法删除版本：该版本下存在关联数据，请先解除关联关系后再删除。关联项：{', '.join(relation_details)}",
            details={
                "task_relations": task_relations_count,
                "defect_relations": defect_relations_count,
                "requirement_relations": requirement_relations_count,
                "release_records": release_records_count
            },
            code=400
        )
    
    # 没有关联关系，可以删除
    # 删除相关数据（虽然已经确认没有关联，但为了数据完整性，保留清理逻辑）
    await db.version_task_relations.delete_many({"version_id": version_obj_id})
    await db.version_defect_relations.delete_many({"version_id": version_obj_id})
    await db.version_requirement_relations.delete_many({"version_id": version_obj_id})
    await db.release_records.delete_many({"version_id": version_obj_id})
    
    # 保存版本信息用于通知
    version_name = version.get("name", "未知版本")
    
    # 删除版本
    await db.versions.delete_one({"_id": version_obj_id})
    
    # 发送版本删除通知
    try:
        user_id = ObjectId(current_user["user_id"])
        current_user_obj = await db.users.find_one({"_id": user_id})
        current_user_name = current_user_obj.get("name") or current_user_obj.get("username", "未知用户") if current_user_obj else "未知用户"
        
        # 获取项目信息
        project = await db.projects.find_one({"_id": version["project_id"]})
        project_name = project.get("name", "未知项目") if project else "未知项目"
        
        # 确定通知接收者：项目成员（排除当前用户）
        notification_recipients = set()
        
        # 添加项目创建人（如果不是当前用户）
        if project and project.get("created_by") and str(project["created_by"]) != current_user["user_id"]:
            notification_recipients.add(str(project["created_by"]))
        
        # 添加项目成员（排除当前用户）
        if project:
            for member in project.get("members", []):
                member_id = member.get("user_id")
                if member_id and str(member_id) != current_user["user_id"]:
                    notification_recipients.add(str(member_id))
        
        # 发送通知
        notification_tasks = []
        
        for recipient_id in notification_recipients:
            notification_data = NotificationCreate(
                user_id=recipient_id,
                type=NotificationType.VERSION_DELETED,
                title=f"版本删除：{version_name}",
                content=f"{current_user_name} 删除了项目「{project_name}」中的版本「{version_name}」（{version.get('version_number', '未知版本号')}）",
                related_type=RelatedObjectType.VERSION,
                related_id=version_id,
                metadata={"project_id": str(version["project_id"]), "project_name": project_name}
            )
            notification_tasks.append(
                NotificationService.create_notification(
                    db=db,
                    notification_data=notification_data,
                    send_email=False
                )
            )
        
        # 异步发送所有通知
        if notification_tasks:
            asyncio.create_task(asyncio.gather(*notification_tasks, return_exceptions=True))
    except Exception as e:
        logger.warning(f"发送版本删除通知失败: {str(e)}")
    
    return success_response(message="删除版本成功")

# ========== 原有接口继续 ==========

@router.post("/{version_id}/transition-approval", response_model=ApiResponse, summary="提交状态流转审批申请")
async def submit_transition_approval(
    version_id: str,
    approval_data: dict = Body(..., description="审批申请数据"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """提交状态流转审批申请"""
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    to_status = approval_data.get("to_status")
    reason = approval_data.get("reason")
    approval_flow_type = approval_data.get("approval_flow_type", "simple")
    
    if not to_status:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="to_status is required"
        )
    
    service = VersionService(db)
    version_doc = await db.versions.find_one({"_id": version_obj_id})
    if not version_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    await service._check_project_access(version_doc["project_id"], current_user)
    
    # 从状态管理系统获取默认状态
    from app.utils.state_utils import get_default_state_code
    default_status = await get_default_state_code(db, "version")
    current_status = version_doc.get("status") or default_status or ""
    
    # 创建审批请求
    approval_service = service.approval_service
    
    try:
        approval_request = await approval_service.create_approval_request(
            version_obj_id,
            current_status,
            to_status,
            reason,
            current_user,
            completion_data=None,
            approval_flow_type=approval_flow_type
        )
        
        return success_response(
            data=approval_request,
            message="审批申请已提交"
        )
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )


# ========== 原有接口继续 ==========

@router.post("/{version_id}/release", response_model=ApiResponse, summary="发布版本")
async def release_version(
    version_id: str,
    release_data: ReleaseRequest,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    发布版本
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 查询版本
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_RELEASE not in user_permissions:
        # 检查是否是项目管理员或有发布权限的成员
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {
                    "members": {
                        "$elemMatch": {
                            "user_id": ObjectId(current_user.get("user_id")),
                            "role": {"$in": ["admin", "manager"]},
                            "permissions": {"$in": ["version_release"]}
                        }
                    }
                }
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 检查版本状态 - 使用动态状态判断
    validator = get_state_validator(db)
    state_info = await validator.get_state_info("version", version["status"])
    if not state_info:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Version status is invalid"
        )
    # 动态判断是否为可发布状态（包含"就绪"、"测试中"、"预发布"等关键词）
    status_code = state_info.get("code", "").lower()
    status_name = state_info.get("name", "")
    is_releasable = (
        "就绪" in status_name or "测试中" in status_name or "预发布" in status_name or
        status_code in ["ready", "testing", "release_ready", "pre_release", "tested"]
    )
    if not is_releasable:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Version is not ready for release"
        )
    
    # 检查是否已有相同环境的活跃发布记录
    existing_release = await db.release_records.find_one({
        "version_id": version_obj_id,
        "environment": release_data.environment,
        "status": ReleaseStatus.SUCCESS
    })
    if existing_release:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Version is already released to this environment"
        )
    
    # 创建发布记录
    now = datetime.utcnow()
    release_record = {
        "version_id": version_obj_id,
        "release_type": release_data.release_type,
        "environment": release_data.environment,
        "status": ReleaseStatus.IN_PROGRESS,
        "release_date": now,
        "rollback_date": None,
        "notes": release_data.notes,
        "config": release_data.config.model_dump() if release_data.config else {},
        "metadata": release_data.metadata.model_dump() if release_data.metadata else {},
        "created_by": ObjectId(current_user.get("user_id")),
        "created_at": now,
        "updated_at": now
    }
    
    # 插入发布记录
    result = await db.release_records.insert_one(release_record)
    
    # 获取已发布状态代码
    released_status_code = await get_state_code_by_name_keywords(db, "version", ["已发布", "发布", "released"])
    
    # 更新版本状态
    update_data = {
        "status": released_status_code or version["status"],  # 使用动态状态，如果没有找到则保持原状态
        "actual_release_date": now,
        "updated_at": now
    }
    await db.versions.update_one({"_id": version_obj_id}, {"$set": update_data})
    
    # 模拟发布过程（实际项目中这里会调用部署系统）
    # 这里简化为直接标记为成功
    await db.release_records.update_one(
        {"_id": result.inserted_id},
        {"$set": {"status": ReleaseStatus.SUCCESS, "updated_at": datetime.utcnow()}}
    )
    
    # 返回发布记录
    created_record = await db.release_records.find_one({"_id": result.inserted_id})
    
    return success_response(data={
        "id": str(created_record["_id"]),
        "version_id": str(created_record["version_id"]),
        "release_type": created_record["release_type"],
        "environment": created_record["environment"],
        "status": created_record["status"],
        "release_date": created_record["release_date"],
        "rollback_date": created_record.get("rollback_date"),
        "notes": created_record.get("notes"),
        "config": created_record.get("config", {}),
        "metadata": created_record.get("metadata", {}),
        "created_by": str(created_record["created_by"]),
        "created_at": created_record["created_at"],
        "updated_at": created_record["updated_at"]
    }, message="发布版本成功")

@router.post("/{version_id}/rollback", response_model=ApiResponse, summary="回滚版本")
async def rollback_version(
    version_id: str,
    rollback_data: RollbackRequest,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    回滚版本
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 查询版本
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_ROLLBACK not in user_permissions:
        # 检查是否是项目管理员或有回滚权限的成员
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {
                    "members": {
                        "$elemMatch": {
                            "user_id": ObjectId(current_user.get("user_id")),
                            "role": {"$in": ["admin", "manager"]},
                            "permissions": {"$in": ["version_rollback"]}
                        }
                    }
                }
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 查找要回滚的发布记录
    release_record = await db.release_records.find_one({
        "version_id": version_obj_id,
        "environment": rollback_data.environment,
        "status": ReleaseStatus.SUCCESS
    })
    if not release_record:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="No successful release found for this environment"
        )
    
    # 更新发布记录为回滚状态
    now = datetime.utcnow()
    await db.release_records.update_one(
        {"_id": release_record["_id"]},
        {
            "$set": {
                "status": ReleaseStatus.ROLLED_BACK,
                "rollback_date": now,
                "notes": f"{release_record.get('notes', '')} | Rollback: {rollback_data.reason}",
                "updated_at": now
            }
        }
    )
    
    # 如果指定了回滚到的版本，创建新的发布记录
    if rollback_data.rollback_to_version_id:
        try:
            rollback_version_obj_id = ObjectId(rollback_data.rollback_to_version_id)
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid rollback version ID format"
            )
        
        # 验证回滚目标版本
        rollback_version = await db.versions.find_one({"_id": rollback_version_obj_id})
        if not rollback_version:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Rollback target version not found"
            )
        
        # 创建回滚发布记录
        rollback_release_record = {
            "version_id": rollback_version_obj_id,
            "release_type": ReleaseType.ROLLBACK,
            "environment": rollback_data.environment,
            "status": ReleaseStatus.SUCCESS,
            "release_date": now,
            "rollback_date": None,
            "notes": f"Rollback from version {version['version_number']}: {rollback_data.reason}",
            "config": {},
            "metadata": {"rollback_from_version": str(version_obj_id)},
            "created_by": ObjectId(current_user.get("user_id")),
            "created_at": now,
            "updated_at": now
        }
        
        await db.release_records.insert_one(rollback_release_record)
    
    # 获取回滚状态代码
    rolled_back_status_code = await get_state_code_by_name_keywords(db, "version", ["已回滚", "回滚", "rolled_back"])
    
    # 更新原版本状态
    await db.versions.update_one(
        {"_id": version_obj_id},
        {"$set": {"status": rolled_back_status_code or version["status"], "updated_at": now}}  # 使用动态状态，如果没有找到则保持原状态
    )
    
    # 返回更新后的发布记录
    updated_record = await db.release_records.find_one({"_id": release_record["_id"]})
    
    return success_response(data={
        "id": str(updated_record["_id"]),
        "version_id": str(updated_record["version_id"]),
        "release_type": updated_record["release_type"],
        "environment": updated_record["environment"],
        "status": updated_record["status"],
        "release_date": updated_record["release_date"],
        "rollback_date": updated_record.get("rollback_date"),
        "notes": updated_record.get("notes"),
        "config": updated_record.get("config", {}),
        "metadata": updated_record.get("metadata", {}),
        "created_by": str(updated_record["created_by"]),
        "created_at": updated_record["created_at"],
        "updated_at": updated_record["updated_at"]
    }, message="回滚版本成功")

# 版本关联管理
@router.post("/{version_id}/tasks", response_model=ApiResponse, summary="将任务关联到版本")
async def add_task_to_version(
    version_id: str,
    relation_data: VersionTaskRelationCreate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    将任务关联到版本
    """
    requirement_obj_id = None
    requirement_doc = None
    try:
        version_obj_id = ObjectId(version_id)
        task_obj_id = ObjectId(relation_data.task_id)
        if relation_data.requirement_id is not None:
            requirement_obj_id = ObjectId(relation_data.requirement_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid ID format"
        )
    
    # 验证版本和任务存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    task = await db.tasks.find_one({"_id": task_obj_id})
    if not task:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Task not found"
        )

    if requirement_obj_id:
        requirement_doc = await db.requirements.find_one({"_id": requirement_obj_id})
        if not requirement_doc:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Requirement not found"
            )
        if requirement_doc.get("project_id") != version["project_id"]:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Requirement must belong to the same project as the version"
            )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        # 检查是否有项目权限
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 检查任务是否属于同一项目
    if task["project_id"] != version["project_id"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Task must belong to the same project as the version"
        )
    
    # 检查关联是否已存在
    existing_relation = await db.version_task_relations.find_one({
        "version_id": version_obj_id,
        "task_id": task_obj_id
    })
    if existing_relation:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Task is already associated with this version"
        )
    
    # 创建关联记录
    now = datetime.utcnow()
    relation_doc = {
        "version_id": version_obj_id,
        "task_id": task_obj_id,
        "requirement_id": requirement_obj_id,
        "relation_type": relation_data.relation_type,
        "notes": relation_data.notes,
        "created_by": ObjectId(current_user.get("user_id")),
        "created_at": now,
        "updated_at": now
    }
    
    result = await db.version_task_relations.insert_one(relation_doc)
    
    # 返回创建的关联
    created_relation = await db.version_task_relations.find_one({"_id": result.inserted_id})
    requirement_title = None
    if requirement_doc:
        requirement_title = requirement_doc.get("title", "")

    response_payload = {
        "id": str(created_relation["_id"]),
        "version_id": str(created_relation["version_id"]),
        "task_id": str(created_relation["task_id"]),
        "requirement_id": str(created_relation["requirement_id"]) if created_relation.get("requirement_id") else None,
        "requirement_title": requirement_title,
        "relation_type": created_relation["relation_type"],
        "notes": created_relation.get("notes"),
        "created_by": str(created_relation["created_by"]),
        "created_at": created_relation["created_at"],
        "updated_at": created_relation["updated_at"]
    }

    return success_response(data=response_payload, message="添加任务关联成功")

@router.delete("/{version_id}/tasks/{task_id}", response_model=ApiResponse, summary="从版本中移除任务")
async def remove_task_from_version(
    version_id: str,
    task_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    从版本中移除任务关联
    """
    try:
        version_obj_id = ObjectId(version_id)
        task_obj_id = ObjectId(task_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid ID format"
        )
    
    # 查找关联记录
    relation = await db.version_task_relations.find_one({
        "version_id": version_obj_id,
        "task_id": task_obj_id
    })
    if not relation:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Task relation not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        # 检查是否有项目权限
        version = await db.versions.find_one({"_id": version_obj_id})
        if version:
            project = await db.projects.find_one({
                "_id": version["project_id"],
                "$or": [
                    {"created_by": ObjectId(current_user.get("user_id"))},
                    {"members.user_id": ObjectId(current_user.get("user_id"))}
                ]
            })
            if not project:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Permission denied"
                )
    
    # 删除关联
    await db.version_task_relations.delete_one({"_id": relation["_id"]})
    
    return success_response(message="移除任务关联成功")

@router.get("/{version_id}/tasks", response_model=ApiResponse, summary="获取版本关联的任务列表")
async def get_version_tasks(
    version_id: str,
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(20, ge=1, le=100, description="返回的记录数"),
    status: Optional[str] = Query(None, description="任务状态筛选"),
    relation_type: Optional[str] = Query(None, description="关联类型筛选"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本关联的任务列表
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 验证版本存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ not in user_permissions:
        # 检查是否有项目权限
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"is_public": True},
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 构建查询条件
    match_conditions = {"version_id": version_obj_id}
    if relation_type:
        match_conditions["relation_type"] = relation_type
    
    # 构建聚合管道
    pipeline = [
        {"$match": match_conditions},
        {"$lookup": {
            "from": "tasks",
            "localField": "task_id",
            "foreignField": "_id",
            "as": "task"
        }},
        {"$unwind": "$task"},
        {"$lookup": {
            "from": "requirements",
            "localField": "requirement_id",
            "foreignField": "_id",
            "as": "requirement"
        }},
        {"$unwind": {"path": "$requirement", "preserveNullAndEmptyArrays": True}},
        {"$lookup": {
            "from": "users",
            "localField": "task.assignee_id",
            "foreignField": "_id",
            "as": "assignee"
        }},
        {"$unwind": {"path": "$assignee", "preserveNullAndEmptyArrays": True}},
        # 如果指定了状态筛选，添加任务状态过滤
        *([{"$match": {"task.status": status}}] if status else []),
        {"$lookup": {
            "from": "users",
            "localField": "created_by",
            "foreignField": "_id",
            "as": "creator"
        }},
        {"$unwind": {"path": "$creator", "preserveNullAndEmptyArrays": True}},
        {"$project": {
            "id": {"$toString": "$_id"},
            "version_id": {"$toString": "$version_id"},
            "task_id": {"$toString": "$task_id"},
            "requirement_id": {
                "$cond": {
                    "if": {"$ifNull": ["$requirement_id", False]},
                    "then": {"$toString": "$requirement_id"},
                    "else": None
                }
            },
            "requirement_title": {"$ifNull": ["$requirement.title", None]},
            "task_title": "$task.title",
            "task_status": "$task.status",
            "task_priority": "$task.priority",
            "task_assignee": {
                "$cond": {
                    "if": {"$ifNull": ["$task.assignee_id", False]},
                    "then": {"$toString": "$task.assignee_id"},
                    "else": None
                }
            },
            "task_assignee_name": {
                "$ifNull": [
                    "$assignee.name",
                    {"$ifNull": ["$assignee.username", None]}
                ]
            },
            "relation_type": 1,
            "notes": 1,
            "associated_by": {"$toString": "$created_by"},
            "associated_by_name": {"$ifNull": ["$creator.username", ""]},
            "associated_at": "$created_at"
        }},
        {"$sort": {"associated_at": DESCENDING}},
        {"$skip": skip},
        {"$limit": limit}
    ]
    
    # 执行聚合查询
    relations = await db.version_task_relations.aggregate(pipeline).to_list(length=None)
    
    # 获取总数（需要重新计算，因为可能包含状态筛选）
    count_pipeline = [
        {"$match": match_conditions},
        {"$lookup": {
            "from": "tasks",
            "localField": "task_id",
            "foreignField": "_id",
            "as": "task"
        }},
        {"$unwind": "$task"},
        *([{"$match": {"task.status": status}}] if status else []),
        {"$count": "total"}
    ]
    count_result = await db.version_task_relations.aggregate(count_pipeline).to_list(length=1)
    total_count = count_result[0]["total"] if count_result else 0
    
    # 序列化结果
    serialized_relations = [serialize_mongo_result(rel) for rel in relations]
    
    return paginated_response(
        items=serialized_relations,
        total=total_count,
        page=(skip // limit) + 1,
        size=limit,
        message="获取版本任务列表成功"
    )

@router.post("/{version_id}/defects", response_model=ApiResponse, summary="将缺陷关联到版本")
async def add_defect_to_version(
    version_id: str,
    relation_data: VersionDefectRelationCreate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    将缺陷关联到版本
    """
    requirement_obj_id = None
    requirement_doc = None
    task_obj_id = None
    task_doc = None
    parent_defect_obj_id = None
    parent_defect_doc = None
    try:
        version_obj_id = ObjectId(version_id)
        defect_obj_id = ObjectId(relation_data.defect_id)
        if relation_data.requirement_id is not None:
            requirement_obj_id = ObjectId(relation_data.requirement_id)
        if relation_data.task_id is not None:
            task_obj_id = ObjectId(relation_data.task_id)
        if relation_data.parent_defect_id is not None:
            parent_defect_obj_id = ObjectId(relation_data.parent_defect_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid ID format"
        )
    
    # 验证版本和缺陷存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    defect = await db.defects.find_one({"_id": defect_obj_id})
    if not defect:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Defect not found"
        )

    if requirement_obj_id:
        requirement_doc = await db.requirements.find_one({"_id": requirement_obj_id})
        if not requirement_doc:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Requirement not found"
            )
        if requirement_doc.get("project_id") != version["project_id"]:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Requirement must belong to the same project as the version"
            )

    if task_obj_id:
        task_doc = await db.tasks.find_one({"_id": task_obj_id})
        if not task_doc:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Task not found"
            )
        if task_doc.get("project_id") != version["project_id"]:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Task must belong to the same project as the version"
            )

    if parent_defect_obj_id:
        parent_defect_doc = await db.defects.find_one({"_id": parent_defect_obj_id})
        if not parent_defect_doc:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Parent defect not found"
            )
        if parent_defect_doc.get("project_id") != version["project_id"]:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Parent defect must belong to the same project as the version"
            )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        # 检查是否有项目权限
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 检查缺陷是否属于同一项目
    if defect["project_id"] != version["project_id"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Defect must belong to the same project as the version"
        )
    
    # 检查关联是否已存在
    existing_relation = await db.version_defect_relations.find_one({
        "version_id": version_obj_id,
        "defect_id": defect_obj_id
    })
    if existing_relation:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Defect is already associated with this version"
        )
    
    # 创建关联记录
    now = datetime.utcnow()
    relation_doc = {
        "version_id": version_obj_id,
        "defect_id": defect_obj_id,
        "requirement_id": requirement_obj_id,
        "task_id": task_obj_id,
        "parent_defect_id": parent_defect_obj_id,
        "relation_type": relation_data.relation_type,
        "notes": relation_data.notes,
        "created_by": ObjectId(current_user.get("user_id")),
        "created_at": now,
        "updated_at": now
    }
    
    result = await db.version_defect_relations.insert_one(relation_doc)
    
    # 返回创建的关联，包含缺陷详细信息
    created_relation = await db.version_defect_relations.find_one({"_id": result.inserted_id})
    
    # 获取缺陷详细信息
    defect_detail = await db.defects.find_one({"_id": defect_obj_id})
    defect_title = defect_detail.get("title", "") if defect_detail else ""
    defect_status = defect_detail.get("status", "") if defect_detail else ""
    requirement_title = requirement_doc.get("title", "") if requirement_doc else None
    task_title = task_doc.get("title", "") if task_doc else None
    parent_defect_title = parent_defect_doc.get("title", "") if parent_defect_doc else None

    response_payload = {
        "id": str(created_relation["_id"]),
        "version_id": str(created_relation["version_id"]),
        "defect_id": str(created_relation["defect_id"]),
        "defect_title": defect_title,
        "defect_status": defect_status,
        "requirement_id": str(created_relation["requirement_id"]) if created_relation.get("requirement_id") else None,
        "requirement_title": requirement_title,
        "task_id": str(created_relation["task_id"]) if created_relation.get("task_id") else None,
        "task_title": task_title,
        "parent_defect_id": str(created_relation["parent_defect_id"]) if created_relation.get("parent_defect_id") else None,
        "parent_defect_title": parent_defect_title,
        "relation_type": created_relation["relation_type"],
        "notes": created_relation.get("notes"),
        "associated_by": str(created_relation["created_by"]),
        "associated_at": created_relation["created_at"]
    }
    
    return success_response(data=response_payload, message="添加缺陷关联成功")

@router.delete("/{version_id}/defects/{defect_id}", response_model=ApiResponse, summary="从版本中移除缺陷")
async def remove_defect_from_version(
    version_id: str,
    defect_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    从版本中移除缺陷关联
    """
    try:
        version_obj_id = ObjectId(version_id)
        defect_obj_id = ObjectId(defect_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid ID format"
        )
    
    # 查找关联记录
    relation = await db.version_defect_relations.find_one({
        "version_id": version_obj_id,
        "defect_id": defect_obj_id
    })
    if not relation:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Defect relation not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        # 检查是否有项目权限
        version = await db.versions.find_one({"_id": version_obj_id})
        if version:
            project = await db.projects.find_one({
                "_id": version["project_id"],
                "$or": [
                    {"created_by": ObjectId(current_user.get("user_id"))},
                    {"members.user_id": ObjectId(current_user.get("user_id"))}
                ]
            })
            if not project:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Permission denied"
                )
    
    # 删除关联
    await db.version_defect_relations.delete_one({"_id": relation["_id"]})
    
    return success_response(message="移除缺陷关联成功")

@router.get("/{version_id}/defects", response_model=ApiResponse, summary="获取版本关联的缺陷列表")
async def get_version_defects(
    version_id: str,
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(20, ge=1, le=100, description="返回的记录数"),
    status: Optional[str] = Query(None, description="缺陷状态筛选"),
    relation_type: Optional[str] = Query(None, description="关联类型筛选"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本关联的缺陷列表
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 验证版本存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ not in user_permissions:
        # 检查是否有项目权限
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"is_public": True},
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 构建查询条件
    match_conditions = {"version_id": version_obj_id}
    if relation_type:
        match_conditions["relation_type"] = relation_type
    
    # 构建聚合管道
    pipeline = [
        {"$match": match_conditions},
        {"$lookup": {
            "from": "defects",
            "localField": "defect_id",
            "foreignField": "_id",
            "as": "defect"
        }},
        {"$unwind": "$defect"},
        {"$lookup": {
            "from": "requirements",
            "localField": "requirement_id",
            "foreignField": "_id",
            "as": "requirement"
        }},
        {"$unwind": {"path": "$requirement", "preserveNullAndEmptyArrays": True}},
        {"$lookup": {
            "from": "tasks",
            "localField": "task_id",
            "foreignField": "_id",
            "as": "task"
        }},
        {"$unwind": {"path": "$task", "preserveNullAndEmptyArrays": True}},
        {"$lookup": {
            "from": "defects",
            "localField": "parent_defect_id",
            "foreignField": "_id",
            "as": "parent_defect"
        }},
        {"$unwind": {"path": "$parent_defect", "preserveNullAndEmptyArrays": True}},
        {"$lookup": {
            "from": "users",
            "localField": "defect.assignee_id",
            "foreignField": "_id",
            "as": "defect_assignee"
        }},
        {"$unwind": {"path": "$defect_assignee", "preserveNullAndEmptyArrays": True}},
        # 如果指定了状态筛选，添加缺陷状态过滤
        *([{"$match": {"defect.status": status}}] if status else []),
        {"$lookup": {
            "from": "users",
            "localField": "created_by",
            "foreignField": "_id",
            "as": "creator"
        }},
        {"$unwind": {"path": "$creator", "preserveNullAndEmptyArrays": True}},
        {"$project": {
            "id": {"$toString": "$_id"},
            "version_id": {"$toString": "$version_id"},
            "defect_id": {"$toString": "$defect_id"},
            "defect_title": "$defect.title",
            "defect_status": "$defect.status",
            "defect_priority": "$defect.priority",
            "defect_severity": "$defect.severity",
            "defect_assignee": {
                "$cond": {
                    "if": {"$ifNull": ["$defect.assignee_id", False]},
                    "then": {"$toString": "$defect.assignee_id"},
                    "else": None
                }
            },
            "defect_assignee_name": {
                "$ifNull": [
                    "$defect_assignee.name",
                    {"$ifNull": ["$defect_assignee.username", None]}
                ]
            },
            "requirement_id": {
                "$cond": {
                    "if": {"$ifNull": ["$requirement_id", False]},
                    "then": {"$toString": "$requirement_id"},
                    "else": None
                }
            },
            "requirement_title": {"$ifNull": ["$requirement.title", None]},
            "task_id": {
                "$cond": {
                    "if": {"$ifNull": ["$task_id", False]},
                    "then": {"$toString": "$task_id"},
                    "else": None
                }
            },
            "task_title": {"$ifNull": ["$task.title", None]},
            "parent_defect_id": {
                "$cond": {
                    "if": {"$ifNull": ["$parent_defect_id", False]},
                    "then": {"$toString": "$parent_defect_id"},
                    "else": None
                }
            },
            "parent_defect_title": {"$ifNull": ["$parent_defect.title", None]},
            "relation_type": 1,
            "notes": 1,
            "associated_by": {"$toString": "$created_by"},
            "associated_by_name": {"$ifNull": ["$creator.username", ""]},
            "associated_at": "$created_at"
        }},
        {"$sort": {"associated_at": DESCENDING}},
        {"$skip": skip},
        {"$limit": limit}
    ]
    
    # 执行聚合查询
    relations = await db.version_defect_relations.aggregate(pipeline).to_list(length=None)
    
    # 获取总数（需要重新计算，因为可能包含状态筛选）
    count_pipeline = [
        {"$match": match_conditions},
        {"$lookup": {
            "from": "defects",
            "localField": "defect_id",
            "foreignField": "_id",
            "as": "defect"
        }},
        {"$unwind": "$defect"},
        *([{"$match": {"defect.status": status}}] if status else []),
        {"$count": "total"}
    ]
    count_result = await db.version_defect_relations.aggregate(count_pipeline).to_list(length=1)
    total_count = count_result[0]["total"] if count_result else 0
    
    # 序列化结果
    serialized_relations = [serialize_mongo_result(rel) for rel in relations]
    
    return paginated_response(
        items=serialized_relations,
        total=total_count,
        page=(skip // limit) + 1,
        size=limit,
        message="获取版本缺陷列表成功"
    )

# 版本比较和统计功能
@router.get("/{version_id}/compare/{target_version_id}", response_model=ApiResponse, summary="比较两个版本")
async def compare_versions(
    version_id: str,
    target_version_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    比较两个版本
    """
    try:
        version_obj_id = ObjectId(version_id)
        target_version_obj_id = ObjectId(target_version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 查询两个版本
    version1 = await db.versions.find_one({"_id": version_obj_id})
    version2 = await db.versions.find_one({"_id": target_version_obj_id})
    
    if not version1 or not version2:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="One or both versions not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ_ALL not in user_permissions:
        # 检查用户是否有两个版本所属项目的权限
        for version in [version1, version2]:
            project = await db.projects.find_one({
                "_id": version["project_id"],
                "$or": [
                    {"is_public": True},
                    {"created_by": ObjectId(current_user.get("user_id"))},
                    {"members.user_id": ObjectId(current_user.get("user_id"))}
                ]
            })
            if not project:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Permission denied"
                )
    
    # 获取版本1的任务和缺陷
    version1_tasks = await db.version_task_relations.find({"version_id": version_obj_id}).to_list(None)
    version1_defects = await db.version_defect_relations.find({"version_id": version_obj_id}).to_list(None)
    
    # 获取版本2的任务和缺陷
    version2_tasks = await db.version_task_relations.find({"version_id": target_version_obj_id}).to_list(None)
    version2_defects = await db.version_defect_relations.find({"version_id": target_version_obj_id}).to_list(None)
    
    # 计算差异
    version1_task_ids = {str(rel["task_id"]) for rel in version1_tasks}
    version2_task_ids = {str(rel["task_id"]) for rel in version2_tasks}
    
    version1_defect_ids = {str(rel["defect_id"]) for rel in version1_defects}
    version2_defect_ids = {str(rel["defect_id"]) for rel in version2_defects}
    
    # 任务差异
    added_tasks = version2_task_ids - version1_task_ids
    removed_tasks = version1_task_ids - version2_task_ids
    common_tasks = version1_task_ids & version2_task_ids
    
    # 缺陷差异
    added_defects = version2_defect_ids - version1_defect_ids
    removed_defects = version1_defect_ids - version2_defect_ids
    common_defects = version1_defect_ids & version2_defect_ids
    
    # 获取详细信息
    async def get_task_details(task_ids):
        if not task_ids:
            return []
        object_ids = [ObjectId(tid) for tid in task_ids]
        tasks = await db.tasks.find({"_id": {"$in": object_ids}}).to_list(None)
        return [
            {
                "id": str(task["_id"]),
                "title": task["title"],
                "status": task["status"],
                "priority": task["priority"]
            }
            for task in tasks
        ]
    
    async def get_defect_details(defect_ids):
        if not defect_ids:
            return []
        object_ids = [ObjectId(did) for did in defect_ids]
        defects = await db.defects.find({"_id": {"$in": object_ids}}).to_list(None)
        return [
            {
                "id": str(defect["_id"]),
                "title": defect["title"],
                "status": defect["status"],
                "priority": defect["priority"],
                "severity": defect["severity"]
            }
            for defect in defects
        ]
    
    # 构建比较结果
    comparison = {
        "version1": {
            "id": str(version1["_id"]),
            "name": version1["name"],
            "version_number": version1["version_number"],
            "status": version1["status"]
        },
        "version2": {
            "id": str(version2["_id"]),
            "name": version2["name"],
            "version_number": version2["version_number"],
            "status": version2["status"]
        },
        "task_differences": {
            "added": await get_task_details(added_tasks),
            "removed": await get_task_details(removed_tasks),
            "common_count": len(common_tasks)
        },
        "defect_differences": {
            "added": await get_defect_details(added_defects),
            "removed": await get_defect_details(removed_defects),
            "common_count": len(common_defects)
        },
        "summary": {
            "total_task_changes": len(added_tasks) + len(removed_tasks),
            "total_defect_changes": len(added_defects) + len(removed_defects),
            "tasks_added": len(added_tasks),
            "tasks_removed": len(removed_tasks),
            "defects_added": len(added_defects),
            "defects_removed": len(removed_defects)
        }
    }
    
    return success_response(data=comparison, message="版本比较成功")

@router.get("/statistics", response_model=ApiResponse, summary="获取版本统计信息")
async def get_version_statistics(
    project_id: Optional[str] = Query(None, description="项目ID筛选"),
    start_date: Optional[datetime] = Query(None, description="开始日期"),
    end_date: Optional[datetime] = Query(None, description="结束日期"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本统计信息
    """
    # 构建查询条件
    query = {}
    
    # 权限控制
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ_ALL not in user_permissions:
        # 获取用户有权限的项目ID列表
        project_query = {
            "$or": [
                {"is_public": True},
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        }
        project_cursor = db.projects.find(project_query, {"_id": 1})
        accessible_project_ids = [project["_id"] async for project in project_cursor]
        
        if accessible_project_ids:
            query["project_id"] = {"$in": accessible_project_ids}
        else:
            # 用户没有任何项目权限，返回空统计
            return success_response(data={
                "total_versions": 0,
                "status_distribution": {},
                "release_type_distribution": {},
                "environment_distribution": {},
                "monthly_creation_trend": [],
                "project_version_counts": [],
                "average_tasks_per_version": 0.0,
                "average_defects_per_version": 0.0,
                "release_success_rate": 0.0
            }, message="获取版本统计信息成功")
    
    if project_id:
        try:
            query["project_id"] = ObjectId(project_id)
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid project_id format"
            )
    
    if start_date or end_date:
        date_query = {}
        if start_date:
            date_query["$gte"] = start_date
        if end_date:
            date_query["$lte"] = end_date
        query["created_at"] = date_query
    
    # 获取版本统计
    versions = await db.versions.find(query).to_list(None)
    total_versions = len(versions)
    
    if total_versions == 0:
        return success_response(data={
            "total_versions": 0,
            "status_distribution": {},
            "release_type_distribution": {},
            "environment_distribution": {},
            "monthly_creation_trend": [],
            "project_version_counts": [],
            "average_tasks_per_version": 0.0,
            "average_defects_per_version": 0.0,
            "release_success_rate": 0.0
        }, message="获取版本统计信息成功")
    
    # 状态分布
    status_distribution = {}
    for version in versions:
        status = version["status"]
        status_distribution[status] = status_distribution.get(status, 0) + 1
    
    # 发布类型分布
    release_type_distribution = {}
    for version in versions:
        release_type = version["release_type"]
        release_type_distribution[release_type] = release_type_distribution.get(release_type, 0) + 1
    
    # 环境分布
    environment_distribution = {}
    for version in versions:
        environment = version["environment"]
        environment_distribution[environment] = environment_distribution.get(environment, 0) + 1
    
    # 月度创建趋势
    from collections import defaultdict
    monthly_trend = defaultdict(int)
    for version in versions:
        month_key = version["created_at"].strftime("%Y-%m")
        monthly_trend[month_key] += 1
    
    monthly_creation_trend = [
        {"month": month, "count": count}
        for month, count in sorted(monthly_trend.items())
    ]
    
    # 项目版本数量
    project_counts = defaultdict(int)
    project_names = {}
    for version in versions:
        project_id = version["project_id"]
        project_counts[project_id] += 1
        if project_id not in project_names:
            project = await db.projects.find_one({"_id": project_id}, {"name": 1})
            project_names[project_id] = project["name"] if project else "Unknown"
    
    project_version_counts = [
        {"project_id": str(pid), "project_name": project_names[pid], "version_count": count}
        for pid, count in project_counts.items()
    ]
    
    # 平均任务和缺陷数量
    version_ids = [version["_id"] for version in versions]
    
    total_task_relations = await db.version_task_relations.count_documents({"version_id": {"$in": version_ids}})
    total_defect_relations = await db.version_defect_relations.count_documents({"version_id": {"$in": version_ids}})
    
    average_tasks_per_version = total_task_relations / total_versions if total_versions > 0 else 0.0
    average_defects_per_version = total_defect_relations / total_versions if total_versions > 0 else 0.0
    
    # 发布成功率
    total_releases = await db.release_records.count_documents({"version_id": {"$in": version_ids}})
    successful_releases = await db.release_records.count_documents({
        "version_id": {"$in": version_ids},
        "status": ReleaseStatus.SUCCESS
    })
    
    release_success_rate = (successful_releases / total_releases * 100) if total_releases > 0 else 0.0
    
    return success_response(data={
        "total_versions": total_versions,
        "status_distribution": status_distribution,
        "release_type_distribution": release_type_distribution,
        "environment_distribution": environment_distribution,
        "monthly_creation_trend": monthly_creation_trend,
        "project_version_counts": project_version_counts,
        "average_tasks_per_version": round(average_tasks_per_version, 2),
        "average_defects_per_version": round(average_defects_per_version, 2),
        "release_success_rate": round(release_success_rate, 2)
    }, message="获取版本统计信息成功")

# 版本需求关联管理
@router.post("/{version_id}/requirements", response_model=ApiResponse, summary="将需求关联到版本")
async def add_requirement_to_version(
    version_id: str,
    relation_data: VersionRequirementCreate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    将需求关联到版本
    """
    try:
        version_obj_id = ObjectId(version_id)
        requirement_obj_id = ObjectId(relation_data.requirement_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid ID format"
        )
    
    # 验证版本和需求存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    requirement = await db.requirements.find_one({"_id": requirement_obj_id})
    if not requirement:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Requirement not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        # 检查是否有项目权限
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 检查需求是否属于同一项目
    if requirement["project_id"] != version["project_id"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Requirement must belong to the same project as the version"
        )
    
    # 检查关联是否已存在
    existing_relation = await db.version_requirement_relations.find_one({
        "version_id": version_obj_id,
        "requirement_id": requirement_obj_id
    })
    if existing_relation:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Requirement is already associated with this version"
        )
    
    # 创建关联记录
    now = datetime.utcnow()
    relation_doc = {
        "version_id": version_obj_id,
        "requirement_id": requirement_obj_id,
        "relation_type": relation_data.relation_type,
        "notes": relation_data.notes,
        "created_by": ObjectId(current_user.get("user_id")),
        "created_at": now,
        "updated_at": now
    }
    
    result = await db.version_requirement_relations.insert_one(relation_doc)
    
    # 返回创建的关联
    created_relation = await db.version_requirement_relations.find_one({"_id": result.inserted_id})
    
    return success_response(data={
        "id": str(created_relation["_id"]),
        "version_id": str(created_relation["version_id"]),
        "requirement_id": str(created_relation["requirement_id"]),
        "relation_type": created_relation["relation_type"],
        "notes": created_relation.get("notes"),
        "created_by": str(created_relation["created_by"]),
        "created_at": created_relation["created_at"],
        "updated_at": created_relation["updated_at"]
    }, message="添加需求关联成功")

@router.delete("/{version_id}/requirements/{requirement_id}", response_model=ApiResponse, summary="从版本中移除需求")
async def remove_requirement_from_version(
    version_id: str,
    requirement_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    从版本中移除需求关联
    """
    try:
        version_obj_id = ObjectId(version_id)
        requirement_obj_id = ObjectId(requirement_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid ID format"
        )
    
    # 查找关联记录
    relation = await db.version_requirement_relations.find_one({
        "version_id": version_obj_id,
        "requirement_id": requirement_obj_id
    })
    if not relation:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Requirement relation not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        # 检查是否有项目权限
        version = await db.versions.find_one({"_id": version_obj_id})
        if version:
            project = await db.projects.find_one({
                "_id": version["project_id"],
                "$or": [
                    {"created_by": ObjectId(current_user.get("user_id"))},
                    {"members.user_id": ObjectId(current_user.get("user_id"))}
                ]
            })
            if not project:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Permission denied"
                )
    
    # 删除关联
    await db.version_requirement_relations.delete_one({"_id": relation["_id"]})
    
    return success_response(message="移除需求关联成功")

@router.get("/{version_id}/requirements", response_model=ApiResponse, summary="获取版本关联的需求列表")
async def get_version_requirements(
    version_id: str,
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(20, ge=1, le=100, description="返回的记录数"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本关联的需求列表
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 验证版本存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查 - 使用统一的权限检查函数
    await check_version_permission(db, version_obj_id, current_user, Permissions.VERSION_READ)
    
    # 构建聚合管道
    pipeline = [
        {"$match": {"version_id": version_obj_id}},
        {"$lookup": {
            "from": "requirements",
            "localField": "requirement_id",
            "foreignField": "_id",
            "as": "requirement"
        }},
        # 使用 preserveNullAndEmptyArrays 保留没有匹配需求的关联关系
        {"$unwind": {"path": "$requirement", "preserveNullAndEmptyArrays": True}},
        # 过滤掉需求不存在的情况（可选，如果希望显示所有关联关系，可以注释掉）
        {"$match": {"requirement": {"$ne": None}}},
        {"$lookup": {
            "from": "users",
            "localField": "created_by",
            "foreignField": "_id",
            "as": "creator"
        }},
        {"$unwind": {"path": "$creator", "preserveNullAndEmptyArrays": True}},
        {"$project": {
            "id": {"$toString": "$_id"},
            "version_id": {"$toString": "$version_id"},
            "requirement_id": {"$toString": "$requirement_id"},
            "relation_type": 1,
            "notes": 1,
            "created_by": {"$toString": "$created_by"},
            "created_at": 1,
            "updated_at": 1,
            "requirement": {
                "id": {"$toString": "$requirement._id"},
                "title": "$requirement.title",
                "description": "$requirement.description",
                "status": "$requirement.status",
                "priority": "$requirement.priority",
                "requirement_type": "$requirement.requirement_type",  # 修正字段名
                "project_id": {"$toString": "$requirement.project_id"},
                "assignee_id": {"$ifNull": [{"$toString": "$requirement.assignee_id"}, None]},
                "reporter_id": {"$toString": "$requirement.reporter_id"},
                "start_date": "$requirement.start_date",
                "due_date": "$requirement.due_date"
            },
            "creator": {
                "id": {"$toString": "$creator._id"},
                "username": "$creator.username",
                "email": "$creator.email"
            }
        }},
        {"$sort": {"created_at": DESCENDING}}
    ]
    
    # 获取总数（只统计有效关联的需求）
    count_pipeline = [
        {"$match": {"version_id": version_obj_id}},
        {"$lookup": {
            "from": "requirements",
            "localField": "requirement_id",
            "foreignField": "_id",
            "as": "requirement"
        }},
        {"$unwind": {"path": "$requirement", "preserveNullAndEmptyArrays": True}},
        {"$match": {"requirement": {"$ne": None}}},
        {"$count": "total"}
    ]
    
    try:
        # 先获取总数
        count_result = await db.version_requirement_relations.aggregate(count_pipeline).to_list(length=1)
        total_count = count_result[0]["total"] if count_result and count_result[0].get("total") else 0
        
        # 添加分页
        pipeline.append({"$skip": skip})
        pipeline.append({"$limit": limit})
        
        # 执行聚合查询
        relations_cursor = db.version_requirement_relations.aggregate(pipeline)
        relations = await relations_cursor.to_list(length=limit)
        
        # 序列化结果
        serialized_relations = []
        if relations:
            for rel in relations:
                serialized_rel = serialize_mongo_result(rel)
                serialized_relations.append(serialized_rel)
        
        # 计算页码（从 skip 和 limit 计算）
        page = (skip // limit) + 1 if limit > 0 else 1
        
        # 返回标准化的分页响应
        return paginated_response(
            items=serialized_relations,
            total=total_count,
            page=page,
            size=limit,
            message="获取版本需求列表成功"
        )
    except HTTPException:
        # 重新抛出HTTP异常
        raise
    except Exception as e:
        logger.error(f"获取版本需求列表失败: {str(e)}", exc_info=True)
        await handle_database_error("get_version_requirements", e)


# 新增：高级版本统计分析API
@router.get("/analytics/overview", response_model=ApiResponse, summary="获取版本分析概览")
async def get_version_analytics_overview(
    project_id: Optional[str] = Query(None, description="项目ID筛选"),
    start_date: Optional[datetime] = Query(None, description="开始日期"),
    end_date: Optional[datetime] = Query(None, description="结束日期"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本分析概览
    包含版本趋势、质量指标、发布效率等综合分析
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ_ALL not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    # 构建查询条件
    query = {}
    if project_id:
        try:
            query["project_id"] = ObjectId(project_id)
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid project_id format"
            )
    
    if start_date or end_date:
        date_query = {}
        if start_date:
            date_query["$gte"] = start_date
        if end_date:
            date_query["$lte"] = end_date
        query["created_at"] = date_query
    
    # 获取版本数据
    versions = await db.versions.find(query).to_list(None)
    version_ids = [v["_id"] for v in versions]
    
    # 版本趋势分析
    trend_pipeline = [
        {"$match": query},
        {"$group": {
            "_id": {
                "year": {"$year": "$created_at"},
                "month": {"$month": "$created_at"},
                "status": "$status"
            },
            "count": {"$sum": 1}
        }},
        {"$sort": {"_id.year": 1, "_id.month": 1}}
    ]
    trend_data = await db.versions.aggregate(trend_pipeline).to_list(None)
    
    # 质量指标分析
    quality_metrics = {}
    if version_ids:
        # 缺陷密度分析
        defect_pipeline = [
            {"$match": {"version_id": {"$in": version_ids}}},
            {"$lookup": {
                "from": "defects",
                "localField": "defect_id",
                "foreignField": "_id",
                "as": "defect"
            }},
            {"$unwind": "$defect"},
            {"$group": {
                "_id": "$version_id",
                "total_defects": {"$sum": 1},
                "critical_defects": {
                    "$sum": {"$cond": [{"$eq": ["$defect.severity", "critical"]}, 1, 0]}
                },
                "high_defects": {
                    "$sum": {"$cond": [{"$eq": ["$defect.severity", "high"]}, 1, 0]}
                }
            }}
        ]
        defect_stats = await db.version_defect_relations.aggregate(defect_pipeline).to_list(None)
        
        # 发布效率分析
        release_pipeline = [
            {"$match": {"version_id": {"$in": version_ids}}},
            {"$group": {
                "_id": "$status",
                "count": {"$sum": 1},
                "avg_duration": {
                    "$avg": {
                        "$subtract": ["$release_date", "$created_at"]
                    }
                }
            }}
        ]
        release_stats = await db.release_records.aggregate(release_pipeline).to_list(None)
        
        quality_metrics = {
            "defect_stats": defect_stats,
            "release_stats": release_stats
        }
    
    # 使用动态状态校验统计版本状态
    validator = get_state_validator(db)
    
    # 动态获取活跃状态（包含"开发中"、"测试中"、"预发布"等关键词）
    from app.utils.state_utils import get_state_code_by_name_keywords
    active_statuses = []
    for keywords in [["开发中", "开发", "development"], ["测试中", "测试", "testing"], ["预发布", "发布就绪", "release_ready"]]:
        status_code = await get_state_code_by_name_keywords(db, "version", keywords)
        if status_code:
            active_statuses.append(status_code)
    
    # 动态获取已发布状态
    released_status_code = await get_state_code_by_name_keywords(db, "version", ["已发布", "发布", "released"])
    
    # 动态获取已归档状态
    archived_status_code = await get_state_code_by_name_keywords(db, "version", ["已归档", "归档", "archived"])
    
    active_count = 0
    released_count = 0
    archived_count = 0
    
    for v in versions:
        state_info = await validator.get_state_info("version", v["status"])
        if state_info:
            status_code = state_info.get("code", "")
            if status_code in active_statuses:
                active_count += 1
            elif released_status_code and status_code == released_status_code:
                released_count += 1
            elif archived_status_code and status_code == archived_status_code:
                archived_count += 1
    
    return success_response(data={
        "summary": {
            "total_versions": len(versions),
            "active_versions": active_count,
            "released_versions": released_count,
            "archived_versions": archived_count
        },
        "trend_analysis": trend_data,
        "quality_metrics": quality_metrics,
        "generated_at": datetime.utcnow()
    }, message="获取版本分析概览成功")


@router.get("/analytics/quality-metrics", response_model=ApiResponse, summary="获取版本质量指标详细分析")
async def get_version_quality_metrics(
    project_id: Optional[str] = Query(None, description="项目ID筛选"),
    version_ids: Optional[List[str]] = Query(None, description="版本ID列表"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本质量指标详细分析
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ_ALL not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    # 构建查询条件
    query = {}
    if project_id:
        try:
            query["project_id"] = ObjectId(project_id)
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid project_id format"
            )
    
    if version_ids:
        try:
            query["_id"] = {"$in": [ObjectId(vid) for vid in version_ids]}
        except Exception:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid version_ids format"
            )
    
    versions = await db.versions.find(query).to_list(None)
    version_obj_ids = [v["_id"] for v in versions]
    
    if not version_obj_ids:
        return success_response(data={"metrics": [], "summary": {}}, message="获取版本质量指标成功")
    
    # 详细质量指标分析
    metrics_pipeline = [
        {"$match": {"version_id": {"$in": version_obj_ids}}},
        {"$lookup": {
            "from": "defects",
            "localField": "defect_id",
            "foreignField": "_id",
            "as": "defect"
        }},
        {"$unwind": "$defect"},
        {"$lookup": {
            "from": "versions",
            "localField": "version_id",
            "foreignField": "_id",
            "as": "version"
        }},
        {"$unwind": "$version"},
        {"$group": {
            "_id": "$version_id",
            "version_name": {"$first": "$version.name"},
            "version_number": {"$first": "$version.version_number"},
            "total_defects": {"$sum": 1},
            "critical_defects": {
                "$sum": {"$cond": [{"$eq": ["$defect.severity", "critical"]}, 1, 0]}
            },
            "high_defects": {
                "$sum": {"$cond": [{"$eq": ["$defect.severity", "high"]}, 1, 0]}
            },
            "medium_defects": {
                "$sum": {"$cond": [{"$eq": ["$defect.severity", "medium"]}, 1, 0]}
            },
            "low_defects": {
                "$sum": {"$cond": [{"$eq": ["$defect.severity", "low"]}, 1, 0]}
            },
            "open_defects": {
                # 缺陷打开状态统计已改为动态，通过聚合后的数据在应用层判断
                "$sum": {"$cond": [{"$ne": ["$defect.status", None]}, 1, 0]}
            },
            "resolved_defects": {
                # 缺陷已解决状态统计已改为动态，通过聚合后的数据在应用层判断
                "$sum": 0
            }
        }},
        {"$addFields": {
            "defect_density": {
                "$cond": [
                    {"$gt": ["$total_defects", 0]},
                    {"$divide": [{"$add": ["$critical_defects", "$high_defects"]}, "$total_defects"]},
                    0
                ]
            },
            "resolution_rate": {
                "$cond": [
                    {"$gt": ["$total_defects", 0]},
                    {"$divide": ["$resolved_defects", "$total_defects"]},
                    0
                ]
            }
        }}
    ]
    
    quality_metrics = await db.version_defect_relations.aggregate(metrics_pipeline).to_list(None)
    
    # 计算汇总指标
    if quality_metrics:
        total_defects = sum(m["total_defects"] for m in quality_metrics)
        total_critical = sum(m["critical_defects"] for m in quality_metrics)
        total_resolved = sum(m["resolved_defects"] for m in quality_metrics)
        
        summary = {
            "total_versions_analyzed": len(quality_metrics),
            "total_defects": total_defects,
            "average_defects_per_version": round(total_defects / len(quality_metrics), 2),
            "critical_defect_rate": round((total_critical / total_defects * 100) if total_defects > 0 else 0, 2),
            "overall_resolution_rate": round((total_resolved / total_defects * 100) if total_defects > 0 else 0, 2)
        }
    else:
        summary = {
            "total_versions_analyzed": 0,
            "total_defects": 0,
            "average_defects_per_version": 0,
            "critical_defect_rate": 0,
            "overall_resolution_rate": 0
        }
    
    return success_response(data={
        "metrics": quality_metrics,
        "summary": summary
    }, message="获取版本质量指标成功")


# 批量操作API
@router.post("/bulk/update-status", response_model=ApiResponse, summary="批量更新版本状态")
async def bulk_update_version_status(
    version_ids: List[str] = Body(..., description="版本ID列表"),
    new_status: str = Body(..., description="新状态"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    批量更新版本状态
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    if not version_ids:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Version IDs list cannot be empty"
        )
    
    try:
        version_obj_ids = [ObjectId(vid) for vid in version_ids]
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 验证版本存在并检查权限
    versions = await db.versions.find({"_id": {"$in": version_obj_ids}}).to_list(None)
    if len(versions) != len(version_ids):
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Some versions not found"
        )
    
    # 检查项目权限
    for version in versions:
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"Permission denied for version {version['name']}"
            )
    
    # 验证状态代码
    is_valid = await validate_state_code(db, "version", new_status)
    if not is_valid:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid status value: {new_status}"
        )
    
    # 执行批量更新
    result = await db.versions.update_many(
        {"_id": {"$in": version_obj_ids}},
        {
            "$set": {
                "status": new_status,
                "updated_at": datetime.utcnow()
            }
        }
    )
    
    return success_response(data={
        "updated_count": result.modified_count,
        "requested_count": len(version_ids),
        "new_status": new_status
    }, message="批量更新版本状态成功")


@router.delete("/bulk/delete", response_model=ApiResponse, summary="批量删除版本")
async def bulk_delete_versions(
    version_ids: List[str] = Body(..., description="版本ID列表"),
    force: bool = Body(False, description="强制删除（忽略关联检查）"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    批量删除版本
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_DELETE not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    if not version_ids:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Version IDs list cannot be empty"
        )
    
    try:
        version_obj_ids = [ObjectId(vid) for vid in version_ids]
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 验证版本存在并检查权限
    versions = await db.versions.find({"_id": {"$in": version_obj_ids}}).to_list(None)
    if len(versions) != len(version_ids):
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Some versions not found"
        )
    
    # 检查项目权限
    for version in versions:
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"Permission denied for version {version['name']}"
            )
    
    # 执行删除操作（每个版本单独检查关联关系）
    deleted_count = 0
    errors = []
    
    for version_obj_id in version_obj_ids:
        try:
            # 如果没有强制删除，每个版本都需要单独检查关联关系
            if not force:
                # 检查单个版本的关联关系（测试用例和测试套件已移除，不再关联版本）
                task_count = await db.version_task_relations.count_documents({"version_id": version_obj_id})
                defect_count = await db.version_defect_relations.count_documents({"version_id": version_obj_id})
                requirement_count = await db.version_requirement_relations.count_documents({"version_id": version_obj_id})
                release_count = await db.release_records.count_documents({"version_id": version_obj_id})
                
                if (task_count > 0 or defect_count > 0 or requirement_count > 0 or release_count > 0):
                    # 获取版本信息以便在错误信息中显示
                    version = await db.versions.find_one({"_id": version_obj_id})
                    version_name = version.get("name", version.get("version_number", str(version_obj_id))) if version else str(version_obj_id)
                    relation_details = []
                    if task_count > 0:
                        relation_details.append(f"任务关联({task_count}个)")
                    if defect_count > 0:
                        relation_details.append(f"缺陷关联({defect_count}个)")
                    if requirement_count > 0:
                        relation_details.append(f"需求关联({requirement_count}个)")
                    if release_count > 0:
                        relation_details.append(f"发布记录({release_count}个)")
                    errors.append(f"版本 {version_name} 存在关联数据无法删除：{', '.join(relation_details)}")
                    continue
            
            # 删除关联关系
            await db.version_task_relations.delete_many({"version_id": version_obj_id})
            await db.version_defect_relations.delete_many({"version_id": version_obj_id})
            await db.version_requirement_relations.delete_many({"version_id": version_obj_id})
            await db.release_records.delete_many({"version_id": version_obj_id})
            
            # 删除版本
            result = await db.versions.delete_one({"_id": version_obj_id})
            if result.deleted_count > 0:
                deleted_count += 1
        except Exception as e:
            errors.append(f"删除版本 {version_obj_id} 失败: {str(e)}")
    
    # 如果所有版本都有关联关系，返回错误
    if deleted_count == 0 and errors:
        return error_response(
            error_type="ALL_VERSIONS_HAVE_RELATIONS",
            message="无法批量删除版本：所有选中的版本都存在关联数据",
            details={
                "errors": errors,
                "requested_count": len(version_ids),
                "deleted_count": deleted_count
            },
            code=400
        )
    
    return success_response(data={
        "deleted_count": deleted_count,
        "requested_count": len(version_ids),
        "errors": errors if errors else None
    }, message=f"批量删除完成，成功删除 {deleted_count} 个版本" + (f"，{len(errors)} 个版本删除失败" if errors else ""))


@router.post("/bulk/associate-tasks", response_model=ApiResponse, summary="批量关联任务到版本")
async def bulk_associate_tasks(
    version_ids: List[str] = Body(..., description="版本ID列表"),
    task_ids: List[str] = Body(..., description="任务ID列表"),
    relation_type: str = Body("included", description="关联类型"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    批量关联任务到版本
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    if not version_ids or not task_ids:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Version IDs and Task IDs lists cannot be empty"
        )
    
    try:
        version_obj_ids = [ObjectId(vid) for vid in version_ids]
        task_obj_ids = [ObjectId(tid) for tid in task_ids]
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid ID format"
        )
    
    # 验证版本和任务存在
    versions = await db.versions.find({"_id": {"$in": version_obj_ids}}).to_list(None)
    tasks = await db.tasks.find({"_id": {"$in": task_obj_ids}}).to_list(None)
    
    if len(versions) != len(version_ids):
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Some versions not found"
        )
    
    if len(tasks) != len(task_ids):
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Some tasks not found"
        )
    
    # 创建关联关系
    relations = []
    now = datetime.utcnow()
    
    for version_obj_id in version_obj_ids:
        for task_obj_id in task_obj_ids:
            # 检查是否已存在关联
            existing = await db.version_task_relations.find_one({
                "version_id": version_obj_id,
                "task_id": task_obj_id
            })
            
            if not existing:
                relations.append({
                    "version_id": version_obj_id,
                    "task_id": task_obj_id,
                    "relation_type": relation_type,
                    "created_by": ObjectId(current_user.get("user_id")),
                    "created_at": now,
                    "updated_at": now
                })
    
    if relations:
        result = await db.version_task_relations.insert_many(relations)
        created_count = len(result.inserted_ids)
    else:
        created_count = 0
    
    return success_response(data={
        "created_relations": created_count,
        "total_possible": len(version_ids) * len(task_ids),
        "skipped_existing": (len(version_ids) * len(task_ids)) - created_count
    }, message="批量关联任务成功")


# 高级查询和分析API
@router.get("/dependencies/{version_id}", response_model=ApiResponse, summary="获取版本依赖关系图")
async def get_version_dependencies(
    version_id: str,
    depth: int = Query(3, ge=1, le=10, description="依赖深度"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本依赖关系图
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 验证版本存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ not in user_permissions:
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 递归获取依赖关系
    async def get_dependencies_recursive(vid, current_depth, visited):
        if current_depth > depth or vid in visited:
            return []
        
        visited.add(vid)
        dependencies = []
        
        # 通过任务关联找到依赖的版本
        task_relations = await db.version_task_relations.find({"version_id": vid}).to_list(None)
        task_ids = [rel["task_id"] for rel in task_relations]
        
        if task_ids:
            # 找到这些任务关联的其他版本
            other_relations = await db.version_task_relations.find({
                "task_id": {"$in": task_ids},
                "version_id": {"$ne": vid}
            }).to_list(None)
            
            for rel in other_relations:
                dep_version = await db.versions.find_one({"_id": rel["version_id"]})
                if dep_version:
                    dep_info = {
                        "version_id": str(dep_version["_id"]),
                        "version_name": dep_version["name"],
                        "version_number": dep_version["version_number"],
                        "status": dep_version["status"],
                        "relation_type": rel["relation_type"],
                        "depth": current_depth
                    }
                    dependencies.append(dep_info)
                    
                    # 递归获取更深层的依赖
                    deeper_deps = await get_dependencies_recursive(
                        rel["version_id"], current_depth + 1, visited.copy()
                    )
                    dependencies.extend(deeper_deps)
        
        return dependencies
    
    dependencies = await get_dependencies_recursive(version_obj_id, 1, set())
    
    # 去重并按深度排序
    unique_deps = {}
    for dep in dependencies:
        key = dep["version_id"]
        if key not in unique_deps or dep["depth"] < unique_deps[key]["depth"]:
            unique_deps[key] = dep
    
    sorted_deps = sorted(unique_deps.values(), key=lambda x: x["depth"])
    
    return success_response(data={
        "version": {
            "id": str(version["_id"]),
            "name": version["name"],
            "version_number": version["version_number"],
            "status": version["status"]
        },
        "dependencies": sorted_deps,
        "total_dependencies": len(sorted_deps),
        "max_depth_analyzed": depth
    }, message="获取版本依赖关系成功")


@router.get("/impact-analysis/{version_id}", response_model=ApiResponse, summary="分析版本变更的影响范围")
async def get_version_impact_analysis(
    version_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    分析版本变更的影响范围
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 验证版本存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ not in user_permissions:
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 分析影响范围
    impact_analysis = {
        "version_info": {
            "id": str(version["_id"]),
            "name": version["name"],
            "version_number": version["version_number"],
            "status": version["status"]
        },
        "direct_impacts": {},
        "indirect_impacts": {},
        "risk_assessment": {}
    }
    
    # 直接影响：关联的任务、缺陷、需求
    task_relations = await db.version_task_relations.find({"version_id": version_obj_id}).to_list(None)
    defect_relations = await db.version_defect_relations.find({"version_id": version_obj_id}).to_list(None)
    requirement_relations = await db.version_requirement_relations.find({"version_id": version_obj_id}).to_list(None)
    
    impact_analysis["direct_impacts"] = {
        "tasks": len(task_relations),
        "defects": len(defect_relations),
        "requirements": len(requirement_relations)
    }
    
    # 间接影响：通过任务关联的其他版本
    if task_relations:
        task_ids = [rel["task_id"] for rel in task_relations]
        other_version_relations = await db.version_task_relations.find({
            "task_id": {"$in": task_ids},
            "version_id": {"$ne": version_obj_id}
        }).to_list(None)
        
        affected_version_ids = list(set(rel["version_id"] for rel in other_version_relations))
        affected_versions = await db.versions.find({"_id": {"$in": affected_version_ids}}).to_list(None)
        
        impact_analysis["indirect_impacts"] = {
            "affected_versions": len(affected_versions),
            "version_details": [
                {
                    "id": str(v["_id"]),
                    "name": v["name"],
                    "version_number": v["version_number"],
                    "status": v["status"]
                }
                for v in affected_versions
            ]
        }
    
    # 风险评估
    risk_score = 0
    risk_factors = []
    
    # 基于关联数量的风险
    total_relations = len(task_relations) + len(defect_relations) + len(requirement_relations)
    if total_relations > 50:
        risk_score += 3
        risk_factors.append("High number of relations")
    elif total_relations > 20:
        risk_score += 2
        risk_factors.append("Moderate number of relations")
    
    # 基于版本状态的风险 - 使用动态状态判断
    validator = get_state_validator(db)
    state_info = await validator.get_state_info("version", version["status"])
    if state_info:
        status_code = state_info.get("code", "")
        status_name = state_info.get("name", "")
        # 判断是否已发布状态（包含"已发布"、"发布"等关键词）
        if "发布" in status_name or status_code.lower() in ["released", "published"]:
            risk_score += 3
            risk_factors.append("Version already released")
        # 判断是否发布就绪状态（包含"发布就绪"、"预发布"等关键词）
        elif "发布就绪" in status_name or "预发布" in status_name or status_code.lower() in ["release_ready", "pre_release"]:
            risk_score += 2
            risk_factors.append("Version ready for release")
    
    # 基于间接影响的风险
    if "affected_versions" in impact_analysis["indirect_impacts"]:
        affected_count = impact_analysis["indirect_impacts"]["affected_versions"]
        if affected_count > 10:
            risk_score += 3
            risk_factors.append("High number of affected versions")
        elif affected_count > 5:
            risk_score += 2
            risk_factors.append("Moderate number of affected versions")
    
    risk_level = "Low"
    if risk_score >= 7:
        risk_level = "High"
    elif risk_score >= 4:
        risk_level = "Medium"
    
    impact_analysis["risk_assessment"] = {
        "risk_score": risk_score,
        "risk_level": risk_level,
        "risk_factors": risk_factors,
        "recommendations": [
            "Perform thorough testing before changes",
            "Notify affected teams",
            "Plan rollback strategy",
            "Monitor post-change metrics"
        ] if risk_score >= 4 else [
            "Standard testing procedures",
            "Regular monitoring"
        ]
    }
    
    return success_response(data=impact_analysis, message="获取版本影响分析成功")


@router.get("/change-history/{version_id}", response_model=ApiResponse, summary="获取版本变更历史")
async def get_version_change_history(
    version_id: str,
    limit: int = Query(50, ge=1, le=100, description="返回记录数"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取版本变更历史
    """
    try:
        version_obj_id = ObjectId(version_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version ID format"
        )
    
    # 验证版本存在
    version = await db.versions.find_one({"_id": version_obj_id})
    if not version:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Version not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ not in user_permissions:
        project = await db.projects.find_one({
            "_id": version["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 获取变更历史（这里假设有一个audit_logs集合记录变更）
    # 实际实现中需要在每次更新时记录变更日志
    change_history = []
    
    # 从发布记录获取历史
    release_records = await db.release_records.find(
        {"version_id": version_obj_id}
    ).sort("created_at", -1).limit(limit).to_list(None)
    
    for record in release_records:
        change_history.append({
            "timestamp": record["created_at"],
            "action": f"Release - {record['release_type']}",
            "details": {
                "environment": record["environment"],
                "status": record["status"],
                "notes": record.get("notes", "")
            },
            "user_id": str(record["created_by"]),
            "type": "release"
        })
    
    # 从任务关联获取历史
    task_relations = await db.version_task_relations.find(
        {"version_id": version_obj_id}
    ).sort("created_at", -1).limit(limit).to_list(None)
    
    for relation in task_relations:
        task = await db.tasks.find_one({"_id": relation["task_id"]}, {"title": 1})
        change_history.append({
            "timestamp": relation["created_at"],
            "action": "Task Associated",
            "details": {
                "task_id": str(relation["task_id"]),
                "task_title": task["title"] if task else "Unknown Task",
                "relation_type": relation["relation_type"]
            },
            "user_id": str(relation["created_by"]),
            "type": "task_relation"
        })
    
    # 按时间排序
    change_history.sort(key=lambda x: x["timestamp"], reverse=True)
    
    return success_response(data={
        "version_info": {
            "id": str(version["_id"]),
            "name": version["name"],
            "version_number": version["version_number"]
        },
        "change_history": change_history[:limit],
        "total_changes": len(change_history)
    }, message="获取版本变更历史成功")


# 发布管理增强API
@router.post("/release-plans", response_model=ApiResponse, summary="创建发布计划")
async def create_release_plan(
    plan_data: dict = Body(..., description="发布计划数据"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    创建发布计划
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_CREATE not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    # 验证必要字段
    required_fields = ["name", "version_ids", "planned_date", "environment"]
    for field in required_fields:
        if field not in plan_data:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Missing required field: {field}"
            )
    
    try:
        version_obj_ids = [ObjectId(vid) for vid in plan_data["version_ids"]]
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid version IDs format"
        )
    
    # 验证版本存在
    versions = await db.versions.find({"_id": {"$in": version_obj_ids}}).to_list(None)
    if len(versions) != len(plan_data["version_ids"]):
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Some versions not found"
        )
    
    # 创建发布计划
    now = datetime.utcnow()
    release_plan = {
        "name": plan_data["name"],
        "description": plan_data.get("description", ""),
        "version_ids": version_obj_ids,
        "planned_date": datetime.fromisoformat(plan_data["planned_date"].replace("Z", "+00:00")),
        "environment": plan_data["environment"],
        "status": "planned",
        "approval_status": "pending",
        "created_by": ObjectId(current_user.get("user_id")),
        "created_at": now,
        "updated_at": now,
        "checklist": plan_data.get("checklist", []),
        "risk_assessment": plan_data.get("risk_assessment", {}),
        "rollback_plan": plan_data.get("rollback_plan", "")
    }
    
    result = await db.release_plans.insert_one(release_plan)
    
    # 返回创建的计划
    created_plan = await db.release_plans.find_one({"_id": result.inserted_id})
    created_plan["id"] = str(created_plan.pop("_id"))
    created_plan["version_ids"] = [str(vid) for vid in created_plan["version_ids"]]
    created_plan["created_by"] = str(created_plan["created_by"])
    
    return success_response(data=created_plan, message="创建发布计划成功")


@router.get("/release-plans", response_model=ApiResponse, summary="获取发布计划列表")
async def get_release_plans(
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(20, ge=1, le=100, description="返回的记录数"),
    status: Optional[str] = Query(None, description="状态筛选"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取发布计划列表
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_READ_ALL not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    # 构建查询条件
    query = {}
    if status:
        query["status"] = status
    
    # 获取发布计划
    plans = await db.release_plans.find(query).skip(skip).limit(limit).sort("created_at", -1).to_list(None)
    
    # 转换格式
    result = []
    for plan in plans:
        plan_data = {
            "id": str(plan["_id"]),
            "name": plan["name"],
            "description": plan.get("description", ""),
            "version_ids": [str(vid) for vid in plan["version_ids"]],
            "planned_date": plan["planned_date"],
            "environment": plan["environment"],
            "status": plan["status"],
            "approval_status": plan["approval_status"],
            "created_by": str(plan["created_by"]),
            "created_at": plan["created_at"],
            "updated_at": plan["updated_at"]
        }
        result.append(plan_data)
    
    total_count = await db.release_plans.count_documents(query)
    return paginated_response(
        items=result,
        total=total_count,
        page=(skip // limit) + 1,
        size=limit,
        message="获取发布计划列表成功"
    )


@router.post("/release-plans/{plan_id}/approve", response_model=ApiResponse, summary="审批发布计划")
async def approve_release_plan(
    plan_id: str,
    approval_data: dict = Body(..., description="审批数据"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    审批发布计划
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.VERSION_UPDATE not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Permission denied"
        )
    
    try:
        plan_obj_id = ObjectId(plan_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid plan ID format"
        )
    
    # 验证计划存在
    plan = await db.release_plans.find_one({"_id": plan_obj_id})
    if not plan:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Release plan not found"
        )
    
    try:
        # 更新审批状态
        approval_status = approval_data.get("status", "approved")
        update_data = {
            "approval_status": approval_status,
            "approved_by": ObjectId(current_user.get("user_id")),
            "approved_at": datetime.utcnow(),
            "approval_notes": approval_data.get("notes", ""),
            "updated_at": datetime.utcnow()
        }
        
        if approval_status == "approved":
            update_data["status"] = "approved"
        elif approval_status == "rejected":
            update_data["status"] = "rejected"
        
        result = await db.release_plans.update_one(
            {"_id": plan_obj_id},
            {"$set": update_data}
        )
        
        if result.modified_count == 0:
            logger.warning(f"No release plan was updated for ID: {plan_id}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Failed to update release plan"
            )
        
        return success_response(data={
            "plan_id": plan_id,
            "approval_status": approval_status,
            "approved_by": current_user.get("user_id"),
            "approved_at": update_data["approved_at"]
        }, message="审批发布计划成功")
    except HTTPException:
        raise
    except Exception as e:
        return await handle_database_error("approve_release_plan", e)


# 数据库查询优化API
@router.get("/performance/query-stats", response_model=ApiResponse, summary="获取查询性能统计信息")
async def get_query_performance_stats(
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取查询性能统计信息（仅管理员可用）
    """
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Admin permission required"
        )
    
    try:
        # 获取集合统计信息
        collections_stats = {}
        
        # 版本集合统计
        versions_stats = await db.command("collStats", "versions")
        collections_stats["versions"] = {
            "count": versions_stats.get("count", 0),
            "size": versions_stats.get("size", 0),
            "avgObjSize": versions_stats.get("avgObjSize", 0),
            "indexSizes": versions_stats.get("indexSizes", {})
        }
        
        # 版本关联集合统计
        for collection in ["version_task_relations", "version_defect_relations", "version_requirement_relations"]:
            try:
                stats = await db.command("collStats", collection)
                collections_stats[collection] = {
                    "count": stats.get("count", 0),
                    "size": stats.get("size", 0),
                    "avgObjSize": stats.get("avgObjSize", 0),
                    "indexSizes": stats.get("indexSizes", {})
                }
            except Exception as e:
                logger.warning(f"Failed to get stats for collection {collection}: {str(e)}")
                collections_stats[collection] = {"error": str(e)}
        
        # 获取索引使用情况
        index_usage = {}
        try:
            # 获取版本集合的索引使用统计
            index_stats = await db.versions.aggregate([
                {"$indexStats": {}}
            ]).to_list(None)
            index_usage["versions"] = index_stats
        except Exception as e:
            logger.warning(f"Failed to get index usage stats: {str(e)}")
            index_usage["error"] = str(e)
        
        return success_response(data={
            "collections_stats": collections_stats,
            "index_usage": index_usage,
            "recommendations": [
                "Consider adding compound indexes for frequently queried fields",
                "Monitor slow queries and optimize them",
                "Use projection to limit returned fields",
                "Implement proper pagination for large result sets"
            ]
        }, message="获取查询性能统计成功")
    except Exception as e:
        await handle_database_error("get_query_performance_stats", e)

@router.get("/requirements/{requirement_id}/versions", response_model=ApiResponse, summary="获取需求关联的版本列表")
async def get_requirement_versions(
    requirement_id: str,
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(20, ge=1, le=100, description="返回的记录数"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    获取需求关联的版本列表
    """
    try:
        requirement_obj_id = ObjectId(requirement_id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid requirement ID format"
        )
    
    # 验证需求存在
    requirement = await db.requirements.find_one({"_id": requirement_obj_id})
    if not requirement:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Requirement not found"
        )
    
    # 权限检查
    user_permissions = current_user.get("permissions", [])
    if "*" not in user_permissions and Permissions.REQUIREMENT_READ not in user_permissions:
        # 检查是否有项目权限
        project = await db.projects.find_one({
            "_id": requirement["project_id"],
            "$or": [
                {"created_by": ObjectId(current_user.get("user_id"))},
                {"members.user_id": ObjectId(current_user.get("user_id"))}
            ]
        })
        if not project:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Permission denied"
            )
    
    # 构建聚合管道
    pipeline = [
        {"$match": {"requirement_id": requirement_obj_id}},
        {"$lookup": {
            "from": "versions",
            "localField": "version_id",
            "foreignField": "_id",
            "as": "version"
        }},
        {"$unwind": "$version"},
        {"$lookup": {
            "from": "users",
            "localField": "created_by",
            "foreignField": "_id",
            "as": "creator"
        }},
        {"$unwind": {"path": "$creator", "preserveNullAndEmptyArrays": True}},
        {"$project": {
            "id": {"$toString": "$_id"},
            "version_id": {"$toString": "$version_id"},
            "requirement_id": {"$toString": "$requirement_id"},
            "relation_type": 1,
            "notes": 1,
            "created_by": {"$toString": "$created_by"},
            "created_at": 1,
            "updated_at": 1,
            "version": {
                "id": {"$toString": "$version._id"},
                "name": "$version.name",
                "version": "$version.version",
                "description": "$version.description",
                "status": "$version.status",
                "release_date": "$version.release_date"
            },
            "creator": {
                "id": {"$toString": "$creator._id"},
                "username": "$creator.username",
                "email": "$creator.email"
            }
        }},
        {"$skip": skip},
        {"$limit": limit}
    ]
    
    # 执行聚合查询
    relations = await db.version_requirement_relations.aggregate(pipeline).to_list(length=None)
    
    # 获取总数
    total_count = await db.version_requirement_relations.count_documents({"requirement_id": requirement_obj_id})
    
    # 序列化结果
    serialized_relations = [serialize_mongo_result(rel) for rel in relations]
    
    # 计算页码
    page = (skip // limit) + 1 if limit > 0 else 1
    
    return paginated_response(
        items=serialized_relations,
        total=total_count,
        page=page,
        size=limit,
        message="获取需求关联的版本列表成功"
    )


@router.get("/{version_id}/report", response_model=ApiResponse, summary="生成版本综合报告")
async def generate_version_report(
    version_id: str,
    report_type: str = Query("full", description="报告类型：full-完整报告，summary-摘要报告"),
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Any:
    """
    生成版本综合报告，包含版本信息、任务统计、缺陷统计、测试用例统计等
    """
    try:
        version_object_id = validate_object_id(version_id, "version_id")
    except HTTPException:
        raise
    
    # 验证版本存在
    version = await validate_version_exists(db, version_object_id)
    
    # 权限验证
    user_permissions = current_user.get("permissions", [])
    user_id = ObjectId(current_user.get("user_id"))
    
    # 检查版本所属项目权限
    if version.get("project_id"):
        project_id = version["project_id"]
        if Permissions.ADMIN not in user_permissions:
            project = await db.projects.find_one({
                "_id": project_id,
                "$or": [
                    {"created_by": user_id},
                    {"members.user_id": user_id},
                    {"is_public": True}
                ]
            })
            if not project:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Not enough permissions to access this version"
                )
    
    # 获取项目信息
    project_name = None
    if version.get("project_id"):
        project = await db.projects.find_one({"_id": version["project_id"]}, {"_id": 1, "name": 1})
        if project:
            project_name = project.get("name")
    
    # 统计任务
    task_relations = await db.version_task_relations.find({"version_id": version_object_id}).to_list(length=None)
    task_ids = [rel["task_id"] for rel in task_relations if rel.get("task_id")]
    
    total_tasks = len(task_ids)
    completed_tasks = 0
    if task_ids:
        # 动态获取任务完成状态（包含"已完成"、"完成"、"done"等关键词）
        from app.utils.state_utils import get_completed_state_codes
        task_completed_statuses = await get_completed_state_codes(db, "task")
        if task_completed_statuses:
            completed_tasks = await db.tasks.count_documents({
                "_id": {"$in": task_ids},
                "status": {"$in": task_completed_statuses}
            })
    
    # 统计缺陷
    defect_relations = await db.version_defect_relations.find({"version_id": version_object_id}).to_list(length=None)
    defect_ids = [rel["defect_id"] for rel in defect_relations if rel.get("defect_id")]
    
    total_defects = len(defect_ids)
    resolved_defects = 0
    if defect_ids:
        # 动态获取缺陷已解决状态（包含"已解决"、"解决"、"resolved"等关键词）
        resolved_status_code = await get_state_code_by_name_keywords(db, "defect", ["已解决", "解决", "resolved"])
        closed_status_code = await get_state_code_by_name_keywords(db, "defect", ["已关闭", "关闭", "closed"])
        fixed_status_code = await get_state_code_by_name_keywords(db, "defect", ["已修复", "修复", "fixed"])
        resolved_statuses = [s for s in [resolved_status_code, closed_status_code, fixed_status_code] if s]
        if resolved_statuses:
            resolved_defects = await db.defects.count_documents({
                "_id": {"$in": defect_ids},
                "status": {"$in": resolved_statuses}
            })
    
    # 测试用例和测试执行统计已移除（测试用例不再关联版本）
    # 如果需要测试相关统计，请通过测试报告模块获取
    
    # 构建报告数据
    report_data = {
        "version_id": version_id,
        "version_name": version.get("name"),
        "version_number": version.get("version_number"),
        "version_status": version.get("status"),
        "release_status": version.get("release_status"),
        "release_type": version.get("release_type"),
        "environment": version.get("environment"),
        "project_id": str(version.get("project_id")) if version.get("project_id") else None,
        "project_name": project_name,
        "planned_release_date": version.get("planned_release_date").isoformat() if version.get("planned_release_date") else None,
        "actual_release_date": version.get("actual_release_date").isoformat() if version.get("actual_release_date") else None,
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "summary": {
            "total_tasks": total_tasks,
            "completed_tasks": completed_tasks,
            "task_completion_rate": round((completed_tasks / total_tasks * 100), 2) if total_tasks > 0 else 0,
            "total_defects": total_defects,
            "resolved_defects": resolved_defects,
            "defect_resolution_rate": round((resolved_defects / total_defects * 100), 2) if total_defects > 0 else 0
        },
        "report_type": report_type
    }
    
    # 如果是完整报告，添加更多详细信息
    if report_type == "full":
        # 任务统计详情
        if task_ids:
            task_status_pipeline = [
                {"$match": {"_id": {"$in": task_ids}}},
                {"$group": {"_id": "$status", "count": {"$sum": 1}}}
            ]
            task_status_stats = {}
            async for doc in db.tasks.aggregate(task_status_pipeline):
                task_status_stats[doc["_id"]] = doc["count"]
            report_data["task_status_stats"] = task_status_stats
        
        # 缺陷统计详情
        if defect_ids:
            defect_status_pipeline = [
                {"$match": {"_id": {"$in": defect_ids}}},
                {"$group": {"_id": "$status", "count": {"$sum": 1}}}
            ]
            defect_status_stats = {}
            async for doc in db.defects.aggregate(defect_status_pipeline):
                defect_status_stats[doc["_id"]] = doc["count"]
            report_data["defect_status_stats"] = defect_status_stats
        
        # 测试用例统计已移除（测试用例不再关联版本）
        # 如果需要测试相关统计，请通过测试报告模块获取
    
    return success_response(data=report_data, message="生成版本报告成功")